From: Paul Brossier Date: Sat, 14 Mar 2015 17:06:10 +0000 (+0100) Subject: waf, waflib: update to 1.8.7 X-Git-Tag: 0.4.2~38 X-Git-Url: https://git.aubio.org/?a=commitdiff_plain;h=904702d027b3e5e51e28a12383eecea0b55611da;p=aubio.git waf, waflib: update to 1.8.7 --- diff --git a/waf b/waf index 75496f71..5b7160a3 100755 --- a/waf +++ b/waf @@ -1,6 +1,6 @@ #!/usr/bin/env python # encoding: ISO8859-1 -# Thomas Nagy, 2005-2012 +# Thomas Nagy, 2005-2015 """ Redistribution and use in source and binary forms, with or without @@ -30,13 +30,15 @@ IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. """ -import os, sys +import os, sys, inspect -VERSION="1.7.15" -REVISION="de1cb53b86321cda764be4b3c38c3d20" +VERSION="1.8.7" +REVISION="073060339ba56c09e143ed641610cbec" +GIT="x" INSTALL='' -C1='#+' -C2='#&' +C1='#/' +C2='#-' +C3='#+' cwd = os.getcwd() join = os.path.join @@ -53,8 +55,8 @@ def err(m): print(('\033[91mError: %s\033[0m' % m)) sys.exit(1) -def unpack_wafdir(dir): - f = open(sys.argv[0],'rb') +def unpack_wafdir(dir, src): + f = open(src,'rb') c = 'corrupt archive (%d)' while 1: line = f.readline() @@ -65,13 +67,13 @@ def unpack_wafdir(dir): if f.readline() != b('#<==\n'): err(c % 2) break if not txt: err(c % 3) - txt = txt[1:-1].replace(b(C1), b('\n')).replace(b(C2), b('\r')) + txt = txt[1:-1].replace(b(C1), b('\n')).replace(b(C2), b('\r')).replace(b(C3), b('\x00')) import shutil, tarfile try: shutil.rmtree(dir) except OSError: pass try: - for x in ['Tools', 'extras']: + for x in ('Tools', 'extras'): os.makedirs(join(dir, 'waflib', x)) except OSError: err("Cannot unpack waf lib into %s\nMove waf in a writable directory" % dir) @@ -100,7 +102,7 @@ def unpack_wafdir(dir): finally: t.close() - for x in ['Tools', 'extras']: + for x in ('Tools', 'extras'): os.chmod(join('waflib',x), 493) if sys.hexversion<0x300000f: @@ -127,8 +129,8 @@ def test(dir): pass def find_lib(): - name = sys.argv[0] - base = os.path.dirname(os.path.abspath(name)) + src = os.path.abspath(inspect.getfile(inspect.getmodule(err))) + base, name = os.path.split(src) #devs use $WAFDIR w=test(os.environ.get('WAFDIR', '')) @@ -141,7 +143,7 @@ def find_lib(): err('waf-light requires waflib -> export WAFDIR=/folder') dirname = '%s-%s-%s' % (WAF, VERSION, REVISION) - for i in [INSTALL,'/usr','/usr/local','/opt']: + for i in (INSTALL,'/usr','/usr/local','/opt'): w = test(i + '/lib/' + dirname) if w: return w @@ -151,7 +153,7 @@ def find_lib(): if w: return w #unpack - unpack_wafdir(dir) + unpack_wafdir(dir, src) return dir wafdir = find_lib() diff --git a/waflib/Build.py b/waflib/Build.py index f76933a2..1012da26 100644 --- a/waflib/Build.py +++ b/waflib/Build.py @@ -2,7 +2,7 @@ # encoding: utf-8 # WARNING! Do not edit! http://waf.googlecode.com/git/docs/wafbook/single.html#_obtaining_the_waf_file -import os,sys,errno,re,shutil +import os,sys,errno,re,shutil,stat try: import cPickle except ImportError: @@ -31,7 +31,7 @@ class BuildContext(Context.Context): self.out_dir=kw.get('out_dir',Context.out_dir) self.cache_dir=kw.get('cache_dir',None) if not self.cache_dir: - self.cache_dir=self.out_dir+os.sep+CACHE_DIR + self.cache_dir=os.path.join(self.out_dir,CACHE_DIR) self.all_envs={} self.task_sigs={} self.node_deps={} @@ -42,8 +42,6 @@ class BuildContext(Context.Context): self.jobs=Options.options.jobs self.targets=Options.options.targets self.keep=Options.options.keep - self.cache_global=Options.cache_global - self.nocache=Options.options.nocache self.progress_bar=Options.options.progress_bar self.deps_man=Utils.defaultdict(list) self.current_group=0 @@ -109,23 +107,19 @@ class BuildContext(Context.Context): self.recurse([self.run_dir]) self.pre_build() self.timer=Utils.Timer() - if self.progress_bar: - sys.stderr.write(Logs.colors.cursor_off) try: self.compile() finally: - if self.progress_bar==1: + if self.progress_bar==1 and sys.stderr.isatty(): c=len(self.returned_tasks)or 1 - self.to_log(self.progress_line(c,c,Logs.colors.BLUE,Logs.colors.NORMAL)) - print('') - sys.stdout.flush() - sys.stderr.write(Logs.colors.cursor_on) + m=self.progress_line(c,c,Logs.colors.BLUE,Logs.colors.NORMAL) + Logs.info(m,extra={'stream':sys.stderr,'c1':Logs.colors.cursor_off,'c2':Logs.colors.cursor_on}) Logs.info("Waf: Leaving directory `%s'"%self.variant_dir) self.post_build() def restore(self): try: env=ConfigSet.ConfigSet(os.path.join(self.cache_dir,'build.config.py')) - except(IOError,OSError): + except EnvironmentError: pass else: if env['version']').ljust(cols) - msg=Utils.indicator%(left,bar,right) + msg=Logs.indicator%(left,bar,right) return msg def declare_chain(self,*k,**kw): return TaskGen.declare_chain(*k,**kw) @@ -325,6 +321,7 @@ class BuildContext(Context.Context): for i in range(len(self.groups)): if id(g)==id(self.groups[i]): self.current_group=i + break else: self.current_group=idx def total(self): @@ -473,16 +470,16 @@ class inst(Task.Task): destfile=os.path.join(destpath,y.path_from(self.path)) else: destfile=os.path.join(destpath,y.name) - self.generator.bld.do_install(y.abspath(),destfile,self.chmod) + self.generator.bld.do_install(y.abspath(),destfile,chmod=self.chmod,tsk=self) def exec_install_as(self): destfile=self.get_install_path() - self.generator.bld.do_install(self.inputs[0].abspath(),destfile,self.chmod) + self.generator.bld.do_install(self.inputs[0].abspath(),destfile,chmod=self.chmod,tsk=self) def exec_symlink_as(self): destfile=self.get_install_path() src=self.link if self.relative_trick: src=os.path.relpath(src,os.path.dirname(destfile)) - self.generator.bld.do_link(src,destfile) + self.generator.bld.do_link(src,destfile,tsk=self) class InstallContext(BuildContext): '''installs the targets on the system''' cmd='install' @@ -490,7 +487,12 @@ class InstallContext(BuildContext): super(InstallContext,self).__init__(**kw) self.uninstall=[] self.is_install=INSTALL - def do_install(self,src,tgt,chmod=Utils.O644): + def copy_fun(self,src,tgt,**kw): + if Utils.is_win32 and len(tgt)>259 and not tgt.startswith('\\\\?\\'): + tgt='\\\\?\\'+tgt + shutil.copy2(src,tgt) + os.chmod(tgt,kw.get('chmod',Utils.O644)) + def do_install(self,src,tgt,**kw): d,_=os.path.split(tgt) if not d: raise Errors.WafError('Invalid installation given %r->%r'%(src,tgt)) @@ -510,19 +512,22 @@ class InstallContext(BuildContext): if not self.progress_bar: Logs.info('+ install %s (from %s)'%(tgt,srclbl)) try: + os.chmod(tgt,Utils.O644|stat.S_IMODE(os.stat(tgt).st_mode)) + except EnvironmentError: + pass + try: os.remove(tgt) except OSError: pass try: - shutil.copy2(src,tgt) - os.chmod(tgt,chmod) + self.copy_fun(src,tgt,**kw) except IOError: try: os.stat(src) - except(OSError,IOError): + except EnvironmentError: Logs.error('File %r does not exist'%src) raise Errors.WafError('Could not install the file %r'%tgt) - def do_link(self,src,tgt): + def do_link(self,src,tgt,**kw): d,_=os.path.split(tgt) Utils.check_dir(d) link=False @@ -545,11 +550,12 @@ class InstallContext(BuildContext): if tsk.runnable_status()==Task.ASK_LATER: raise self.WafError('cannot post the task %r'%tsk) tsk.run() - def install_files(self,dest,files,env=None,chmod=Utils.O644,relative_trick=False,cwd=None,add=True,postpone=True): + def install_files(self,dest,files,env=None,chmod=Utils.O644,relative_trick=False,cwd=None,add=True,postpone=True,task=None): tsk=inst(env=env or self.env) tsk.bld=self tsk.path=cwd or self.path tsk.chmod=chmod + tsk.task=task if isinstance(files,waflib.Node.Node): tsk.source=[files] else: @@ -560,18 +566,19 @@ class InstallContext(BuildContext): if add:self.add_to_group(tsk) self.run_task_now(tsk,postpone) return tsk - def install_as(self,dest,srcfile,env=None,chmod=Utils.O644,cwd=None,add=True,postpone=True): + def install_as(self,dest,srcfile,env=None,chmod=Utils.O644,cwd=None,add=True,postpone=True,task=None): tsk=inst(env=env or self.env) tsk.bld=self tsk.path=cwd or self.path tsk.chmod=chmod tsk.source=[srcfile] + tsk.task=task tsk.dest=dest tsk.exec_task=tsk.exec_install_as if add:self.add_to_group(tsk) self.run_task_now(tsk,postpone) return tsk - def symlink_as(self,dest,src,env=None,cwd=None,add=True,postpone=True,relative_trick=False): + def symlink_as(self,dest,src,env=None,cwd=None,add=True,postpone=True,relative_trick=False,task=None): if Utils.is_win32: return tsk=inst(env=env or self.env) @@ -579,6 +586,7 @@ class InstallContext(BuildContext): tsk.dest=dest tsk.path=cwd or self.path tsk.source=[] + tsk.task=task tsk.link=src tsk.relative_trick=relative_trick tsk.exec_task=tsk.exec_symlink_as @@ -591,7 +599,14 @@ class UninstallContext(InstallContext): def __init__(self,**kw): super(UninstallContext,self).__init__(**kw) self.is_install=UNINSTALL - def do_install(self,src,tgt,chmod=Utils.O644): + def rm_empty_dirs(self,tgt): + while tgt: + tgt=os.path.dirname(tgt) + try: + os.rmdir(tgt) + except OSError: + break + def do_install(self,src,tgt,**kw): if not self.progress_bar: Logs.info('- remove %s'%tgt) self.uninstall.append(tgt) @@ -604,25 +619,15 @@ class UninstallContext(InstallContext): Logs.warn('build: some files could not be uninstalled (retry with -vv to list them)') if Logs.verbose>1: Logs.warn('Could not remove %s (error code %r)'%(e.filename,e.errno)) - while tgt: - tgt=os.path.dirname(tgt) - try: - os.rmdir(tgt) - except OSError: - break - def do_link(self,src,tgt): + self.rm_empty_dirs(tgt) + def do_link(self,src,tgt,**kw): try: if not self.progress_bar: Logs.info('- remove %s'%tgt) os.remove(tgt) except OSError: pass - while tgt: - tgt=os.path.dirname(tgt) - try: - os.rmdir(tgt) - except OSError: - break + self.rm_empty_dirs(tgt) def execute(self): try: def runnable_status(self): @@ -754,5 +759,3 @@ class StepContext(BuildContext): else: return pattern.match(node.abspath()) return match -BuildContext.store=Utils.nogc(BuildContext.store) -BuildContext.restore=Utils.nogc(BuildContext.restore) diff --git a/waflib/ConfigSet.py b/waflib/ConfigSet.py index f9fdcc7c..2b2cfe0a 100644 --- a/waflib/ConfigSet.py +++ b/waflib/ConfigSet.py @@ -89,9 +89,9 @@ class ConfigSet(object): self.table[key]=value return value def append_value(self,var,val): - current_value=self._get_list_value_for_modification(var) if isinstance(val,str): val=[val] + current_value=self._get_list_value_for_modification(var) current_value.extend(val) def prepend_value(self,var,val): if isinstance(val,str): diff --git a/waflib/Configure.py b/waflib/Configure.py index 2814e61c..7f328f9b 100644 --- a/waflib/Configure.py +++ b/waflib/Configure.py @@ -2,14 +2,8 @@ # encoding: utf-8 # WARNING! Do not edit! http://waf.googlecode.com/git/docs/wafbook/single.html#_obtaining_the_waf_file -import os,shlex,sys,time +import os,shlex,sys,time,re,shutil from waflib import ConfigSet,Utils,Options,Logs,Context,Build,Errors -try: - from urllib import request -except ImportError: - from urllib import urlopen -else: - urlopen=request.urlopen BREAK='break' CONTINUE='continue' WAF_CONFIG_LOG='config.log' @@ -18,37 +12,6 @@ conf_template='''# project %(app)s configured on %(now)s by # waf %(wafver)s (abi %(abi)s, python %(pyver)x on %(systype)s) # using %(args)s #''' -def download_check(node): - pass -def download_tool(tool,force=False,ctx=None): - for x in Utils.to_list(Context.remote_repo): - for sub in Utils.to_list(Context.remote_locs): - url='/'.join((x,sub,tool+'.py')) - try: - web=urlopen(url) - try: - if web.getcode()!=200: - continue - except AttributeError: - pass - except Exception: - continue - else: - tmp=ctx.root.make_node(os.sep.join((Context.waf_dir,'waflib','extras',tool+'.py'))) - tmp.write(web.read(),'wb') - Logs.warn('Downloaded %s from %s'%(tool,url)) - download_check(tmp) - try: - module=Context.load_tool(tool) - except Exception: - Logs.warn('The tool %s from %s is unusable'%(tool,url)) - try: - tmp.delete() - except Exception: - pass - continue - return module - raise Errors.WafError('Could not load the Waf tool') class ConfigurationContext(Context.Context): '''configures the project''' cmd='configure' @@ -96,6 +59,7 @@ class ConfigurationContext(Context.Context): out=getattr(Context.g_module,Context.OUT,None) if not out: out=Options.lockfile.replace('.lock-waf_%s_'%sys.platform,'').replace('.lock-waf','') + out=os.path.realpath(out) self.bldnode=(os.path.isabs(out)and self.root or self.path).make_node(out) self.bldnode.mkdir() if not os.path.isdir(self.bldnode.abspath()): @@ -139,11 +103,11 @@ class ConfigurationContext(Context.Context): env['files']=self.files env['environ']=dict(self.environ) if not self.env.NO_LOCK_IN_RUN: - env.store(Context.run_dir+os.sep+Options.lockfile) + env.store(os.path.join(Context.run_dir,Options.lockfile)) if not self.env.NO_LOCK_IN_TOP: - env.store(Context.top_dir+os.sep+Options.lockfile) + env.store(os.path.join(Context.top_dir,Options.lockfile)) if not self.env.NO_LOCK_IN_OUT: - env.store(Context.out_dir+os.sep+Options.lockfile) + env.store(os.path.join(Context.out_dir,Options.lockfile)) def prepare_env(self,env): if not env.PREFIX: if Options.options.prefix or Utils.is_win32: @@ -151,9 +115,15 @@ class ConfigurationContext(Context.Context): else: env.PREFIX='' if not env.BINDIR: - env.BINDIR=Utils.subst_vars('${PREFIX}/bin',env) + if Options.options.bindir: + env.BINDIR=os.path.abspath(os.path.expanduser(Options.options.bindir)) + else: + env.BINDIR=Utils.subst_vars('${PREFIX}/bin',env) if not env.LIBDIR: - env.LIBDIR=Utils.subst_vars('${PREFIX}/lib',env) + if Options.options.libdir: + env.LIBDIR=os.path.abspath(os.path.expanduser(Options.options.libdir)) + else: + env.LIBDIR=Utils.subst_vars('${PREFIX}/lib%s'%Utils.lib64(),env) def store(self): n=self.cachedir.make_node('build.config.py') n.write('version = 0x%x\ntools = %r\n'%(Context.HEXVERSION,self.tools)) @@ -162,7 +132,7 @@ class ConfigurationContext(Context.Context): for key in self.all_envs: tmpenv=self.all_envs[key] tmpenv.store(os.path.join(self.cachedir.abspath(),key+Build.CACHE_SUFFIX)) - def load(self,input,tooldir=None,funs=None,download=True): + def load(self,input,tooldir=None,funs=None): tools=Utils.to_list(input) if tooldir:tooldir=Utils.to_list(tooldir) for tool in tools: @@ -173,14 +143,9 @@ class ConfigurationContext(Context.Context): self.tool_cache.append(mag) module=None try: - module=Context.load_tool(tool,tooldir) + module=Context.load_tool(tool,tooldir,ctx=self) except ImportError ,e: - if Options.options.download: - module=download_tool(tool,ctx=self) - if not module: - self.fatal('Could not load the Waf tool %r or download a suitable replacement from the repository (sys.path %r)\n%s'%(tool,sys.path,e)) - else: - self.fatal('Could not load the Waf tool %r from %r (try the --download option?):\n%s'%(tool,sys.path,e)) + self.fatal('Could not load the Waf tool %r from %r\n%s'%(tool,sys.path,e)) except Exception ,e: self.to_log('imp %r (%r & %r)'%(tool,tooldir,funs)) self.to_log(Utils.ex_stack()) @@ -243,14 +208,14 @@ def cmd_to_list(self,cmd): return[cmd] return cmd @conf -def check_waf_version(self,mini='1.6.99',maxi='1.8.0'): - self.start_msg('Checking for waf version in %s-%s'%(str(mini),str(maxi))) +def check_waf_version(self,mini='1.7.99',maxi='1.9.0',**kw): + self.start_msg('Checking for waf version in %s-%s'%(str(mini),str(maxi)),**kw) ver=Context.HEXVERSION if Utils.num2ver(mini)>ver: self.fatal('waf version should be at least %r (%r found)'%(Utils.num2ver(mini),ver)) if Utils.num2ver(maxi) %r'%(filename,path_list,var,ret)) + ret=self.cmd_to_list(filename) + elif self.env[var]: + ret=self.env[var] + ret=self.cmd_to_list(ret) + else: + if not ret: + ret=self.find_binary(filename,exts.split(','),path_list) + if not ret and Utils.winreg: + ret=Utils.get_registry_app_path(Utils.winreg.HKEY_CURRENT_USER,filename) + if not ret and Utils.winreg: + ret=Utils.get_registry_app_path(Utils.winreg.HKEY_LOCAL_MACHINE,filename) + ret=self.cmd_to_list(ret) + if ret: + if len(ret)==1: + retmsg=ret[0] + else: + retmsg=ret + else: + retmsg=False + self.msg("Checking for program '%s'"%msg,retmsg,**kw) + if not kw.get('quiet',None): + self.to_log('find program=%r paths=%r var=%r -> %r'%(filename,path_list,var,ret)) if not ret: - self.fatal(kw.get('errmsg','')or'Could not find the program %s'%','.join(filename)) - if var: + self.fatal(kw.get('errmsg','')or'Could not find the program %r'%filename) + interpreter=kw.get('interpreter',None) + if interpreter is None: + if not Utils.check_exe(ret[0],env=environ): + self.fatal('Program %r is not executable'%ret) self.env[var]=ret + else: + self.env[var]=self.env[interpreter]+ret return ret @conf -def find_perl_program(self,filename,path_list=[],var=None,environ=None,exts=''): +def find_binary(self,filenames,exts,paths): + for f in filenames: + for ext in exts: + exe_name=f+ext + if os.path.isabs(exe_name): + if os.path.isfile(exe_name): + return exe_name + else: + for path in paths: + x=os.path.expanduser(os.path.join(path,exe_name)) + if os.path.isfile(x): + return x + return None +@conf +def run_build(self,*k,**kw): + lst=[str(v)for(p,v)in kw.items()if p!='env'] + h=Utils.h_list(lst) + dir=self.bldnode.abspath()+os.sep+(not Utils.is_win32 and'.'or'')+'conf_check_'+Utils.to_hex(h) try: - app=self.find_program(filename,path_list=path_list,var=var,environ=environ,exts=exts) - except Exception: - self.find_program('perl',var='PERL') - app=self.find_file(filename,os.environ['PATH'].split(os.pathsep)) - if not app: + os.makedirs(dir) + except OSError: + pass + try: + os.stat(dir) + except OSError: + self.fatal('cannot use the configuration test folder %r'%dir) + cachemode=getattr(Options.options,'confcache',None) + if cachemode==1: + try: + proj=ConfigSet.ConfigSet(os.path.join(dir,'cache_run_build')) + except OSError: + pass + except IOError: + pass + else: + ret=proj['cache_run_build'] + if isinstance(ret,str)and ret.startswith('Test does not build'): + self.fatal(ret) + return ret + bdir=os.path.join(dir,'testbuild') + if not os.path.exists(bdir): + os.makedirs(bdir) + self.test_bld=bld=Build.BuildContext(top_dir=dir,out_dir=bdir) + bld.init_dirs() + bld.progress_bar=0 + bld.targets='*' + bld.logger=self.logger + bld.all_envs.update(self.all_envs) + bld.env=kw['env'] + bld.kw=kw + bld.conf=self + kw['build_fun'](bld) + ret=-1 + try: + try: + bld.compile() + except Errors.WafError: + ret='Test does not build: %s'%Utils.ex_stack() + self.fatal(ret) + else: + ret=getattr(bld,'retval',0) + finally: + if cachemode==1: + proj=ConfigSet.ConfigSet() + proj['cache_run_build']=ret + proj.store(os.path.join(dir,'cache_run_build')) + else: + shutil.rmtree(dir) + return ret +@conf +def ret_msg(self,msg,args): + if isinstance(msg,str): + return msg + return msg(args) +@conf +def test(self,*k,**kw): + if not'env'in kw: + kw['env']=self.env.derive() + if kw.get('validate',None): + kw['validate'](kw) + self.start_msg(kw['msg'],**kw) + ret=None + try: + ret=self.run_build(*k,**kw) + except self.errors.ConfigurationError: + self.end_msg(kw['errmsg'],'YELLOW',**kw) + if Logs.verbose>1: raise - if var: - self.env[var]=Utils.to_list(self.env['PERL'])+[app] - self.msg('Checking for %r'%filename,app) + else: + self.fatal('The configuration failed') + else: + kw['success']=ret + if kw.get('post_check',None): + ret=kw['post_check'](kw) + if ret: + self.end_msg(kw['errmsg'],'YELLOW',**kw) + self.fatal('The configuration failed %r'%ret) + else: + self.end_msg(self.ret_msg(kw['okmsg'],kw),**kw) + return ret diff --git a/waflib/Context.py b/waflib/Context.py index ab8d047f..dc66e65a 100644 --- a/waflib/Context.py +++ b/waflib/Context.py @@ -2,12 +2,12 @@ # encoding: utf-8 # WARNING! Do not edit! http://waf.googlecode.com/git/docs/wafbook/single.html#_obtaining_the_waf_file -import os,imp,sys +import os,re,imp,sys from waflib import Utils,Errors,Logs import waflib.Node -HEXVERSION=0x1070f00 -WAFVERSION="1.7.15" -WAFREVISION="f63ac9793de2d4eaae884e55d4ff70a761dcbab2" +HEXVERSION=0x1080700 +WAFVERSION="1.8.7" +WAFREVISION="e5056b9ade7bb224f53baab13a0ce136344ab602" ABI=98 DBFILE='.wafpickle-%s-%d-%d'%(sys.platform,sys.hexversion,ABI) APPNAME='APPNAME' @@ -71,6 +71,14 @@ class Context(ctx): self.logger=None def __hash__(self): return id(self) + def finalize(self): + try: + logger=self.logger + except AttributeError: + pass + else: + Logs.free_logger(logger) + delattr(self,'logger') def load(self,tool_list,*k,**kw): tools=Utils.to_list(tool_list) path=Utils.to_list(kw.get('tooldir','')) @@ -90,7 +98,7 @@ class Context(ctx): self.cur_script=self.stack_path.pop() if self.cur_script: self.path=self.cur_script.parent - def recurse(self,dirs,name=None,mandatory=True,once=True): + def recurse(self,dirs,name=None,mandatory=True,once=True,encoding=None): try: cache=self.recurse_cache except AttributeError: @@ -105,7 +113,7 @@ class Context(ctx): cache[node]=True self.pre_recurse(node) try: - function_code=node.read('rU') + function_code=node.read('rU',encoding) exec(compile(function_code,node.abspath(),'exec'),self.exec_dict) finally: self.post_recurse(node) @@ -116,7 +124,7 @@ class Context(ctx): cache[tup]=True self.pre_recurse(node) try: - wscript_module=load_module(node.abspath()) + wscript_module=load_module(node.abspath(),encoding=encoding) user_function=getattr(wscript_module,(name or self.fun),None) if not user_function: if not mandatory: @@ -140,6 +148,8 @@ class Context(ctx): kw['stdout']=subprocess.PIPE if'stderr'not in kw: kw['stderr']=subprocess.PIPE + if Logs.verbose and not kw['shell']and not Utils.check_exe(cmd[0]): + raise Errors.WafError("Program %s not found!"%cmd[0]) try: if kw['stdout']or kw['stderr']: p=subprocess.Popen(cmd,**kw) @@ -156,14 +166,14 @@ class Context(ctx): if self.logger: self.logger.debug('out: %s'%out) else: - sys.stdout.write(out) + Logs.info(out,extra={'stream':sys.stdout,'c1':''}) if err: if not isinstance(err,str): err=err.decode(sys.stdout.encoding or'iso8859-1') if self.logger: self.logger.error('err: %s'%err) else: - sys.stderr.write(err) + Logs.info(err,extra={'stream':sys.stderr,'c1':''}) return ret def cmd_and_log(self,cmd,**kw): subprocess=Utils.subprocess @@ -179,6 +189,8 @@ class Context(ctx): del kw['output'] else: to_ret=STDOUT + if Logs.verbose and not kw['shell']and not Utils.check_exe(cmd[0]): + raise Errors.WafError("Program %s not found!"%cmd[0]) kw['stdout']=kw['stderr']=subprocess.PIPE if quiet is None: self.to_log(cmd) @@ -222,12 +234,24 @@ class Context(ctx): else: sys.stderr.write(str(msg)) sys.stderr.flush() - def msg(self,msg,result,color=None): - self.start_msg(msg) + def msg(self,*k,**kw): + try: + msg=kw['msg'] + except KeyError: + msg=k[0] + self.start_msg(msg,**kw) + try: + result=kw['result'] + except KeyError: + result=k[1] + color=kw.get('color',None) if not isinstance(color,str): color=result and'GREEN'or'YELLOW' - self.end_msg(result,color) - def start_msg(self,msg): + self.end_msg(result,color,**kw) + def start_msg(self,*k,**kw): + if kw.get('quiet',None): + return + msg=kw.get('msg',None)or k[0] try: if self.in_msg: self.in_msg+=1 @@ -242,10 +266,13 @@ class Context(ctx): for x in(self.line_just*'-',msg): self.to_log(x) Logs.pprint('NORMAL',"%s :"%msg.ljust(self.line_just),sep='') - def end_msg(self,result,color=None): + def end_msg(self,*k,**kw): + if kw.get('quiet',None): + return self.in_msg-=1 if self.in_msg: return + result=kw.get('result',None)or k[0] defcolor='GREEN' if result==True: msg='ok' @@ -255,23 +282,47 @@ class Context(ctx): else: msg=str(result) self.to_log(msg) - Logs.pprint(color or defcolor,msg) + try: + color=kw['color'] + except KeyError: + if len(k)>1 and k[1]in Logs.colors_lst: + color=k[1] + else: + color=defcolor + Logs.pprint(color,msg) def load_special_tools(self,var,ban=[]): global waf_dir - lst=self.root.find_node(waf_dir).find_node('waflib/extras').ant_glob(var) - for x in lst: - if not x.name in ban: - load_tool(x.name.replace('.py','')) + if os.path.isdir(waf_dir): + lst=self.root.find_node(waf_dir).find_node('waflib/extras').ant_glob(var) + for x in lst: + if not x.name in ban: + load_tool(x.name.replace('.py','')) + else: + from zipfile import PyZipFile + waflibs=PyZipFile(waf_dir) + lst=waflibs.namelist() + for x in lst: + if not re.match("waflib/extras/%s"%var.replace("*",".*"),var): + continue + f=os.path.basename(x) + doban=False + for b in ban: + r=b.replace("*",".*") + if re.match(b,f): + doban=True + if not doban: + f=f.replace('.py','') + load_tool(f) cache_modules={} -def load_module(path): +def load_module(path,encoding=None): try: return cache_modules[path] except KeyError: pass module=imp.new_module(WSCRIPT_FILE) try: - code=Utils.readf(path,m='rU') - except(IOError,OSError): + code=Utils.readf(path,m='rU',encoding=encoding) + except EnvironmentError: raise Errors.WafError('Could not read the file %r'%path) module_dir=os.path.dirname(path) sys.path.insert(0,module_dir) @@ -279,11 +330,9 @@ def load_module(path): sys.path.remove(module_dir) cache_modules[path]=module return module -def load_tool(tool,tooldir=None): +def load_tool(tool,tooldir=None,ctx=None): if tool=='java': tool='javaw' - elif tool=='compiler_cc': - tool='compiler_c' else: tool=tool.replace('++','xx') if tooldir: @@ -298,19 +347,14 @@ def load_tool(tool,tooldir=None): for d in tooldir: sys.path.remove(d) else: - global waf_dir - try: - os.stat(os.path.join(waf_dir,'waflib','extras',tool+'.py')) - except OSError: + for x in('waflib.Tools.%s','waflib.extras.%s','waflib.%s','%s'): try: - os.stat(os.path.join(waf_dir,'waflib','Tools',tool+'.py')) - except OSError: - d=tool - else: - d='waflib.Tools.%s'%tool - else: - d='waflib.extras.%s'%tool - __import__(d) - ret=sys.modules[d] + __import__(x%tool) + break + except ImportError: + x=None + if x is None: + __import__(tool) + ret=sys.modules[x%tool] Context.tools[tool]=ret return ret diff --git a/waflib/Logs.py b/waflib/Logs.py index ef624520..713fd56a 100644 --- a/waflib/Logs.py +++ b/waflib/Logs.py @@ -2,72 +2,38 @@ # encoding: utf-8 # WARNING! Do not edit! http://waf.googlecode.com/git/docs/wafbook/single.html#_obtaining_the_waf_file -import os,re,traceback,sys -_nocolor=os.environ.get('NOCOLOR','no')not in('no','0','false') -try: - if not _nocolor: - import waflib.ansiterm -except ImportError: - pass -try: - import threading -except ImportError: - if not'JOBS'in os.environ: - os.environ['JOBS']='1' -else: - wlock=threading.Lock() - class sync_stream(object): - def __init__(self,stream): - self.stream=stream - self.encoding=self.stream.encoding - def write(self,txt): - try: - wlock.acquire() - self.stream.write(txt) - self.stream.flush() - finally: - wlock.release() - def fileno(self): - return self.stream.fileno() - def flush(self): - self.stream.flush() - def isatty(self): - return self.stream.isatty() - if not os.environ.get('NOSYNC',False): - if id(sys.stdout)==id(sys.__stdout__): - sys.stdout=sync_stream(sys.stdout) - sys.stderr=sync_stream(sys.stderr) +import os,re,traceback,sys,types +from waflib import Utils,ansiterm +if not os.environ.get('NOSYNC',False): + if sys.stdout.isatty()and id(sys.stdout)==id(sys.__stdout__): + sys.stdout=ansiterm.AnsiTerm(sys.stdout) + if sys.stderr.isatty()and id(sys.stderr)==id(sys.__stderr__): + sys.stderr=ansiterm.AnsiTerm(sys.stderr) import logging LOG_FORMAT="%(asctime)s %(c1)s%(zone)s%(c2)s %(message)s" HOUR_FORMAT="%H:%M:%S" zones='' verbose=0 colors_lst={'USE':True,'BOLD':'\x1b[01;1m','RED':'\x1b[01;31m','GREEN':'\x1b[32m','YELLOW':'\x1b[33m','PINK':'\x1b[35m','BLUE':'\x1b[01;34m','CYAN':'\x1b[36m','NORMAL':'\x1b[0m','cursor_on':'\x1b[?25h','cursor_off':'\x1b[?25l',} -got_tty=not os.environ.get('TERM','dumb')in['dumb','emacs'] -if got_tty: - try: - got_tty=sys.stderr.isatty()and sys.stdout.isatty() - except AttributeError: - got_tty=False -if(not got_tty and os.environ.get('TERM','dumb')!='msys')or _nocolor: - colors_lst['USE']=False -def get_term_cols(): - return 80 -try: - import struct,fcntl,termios -except ImportError: - pass -else: - if got_tty: - def get_term_cols_real(): - dummy_lines,cols=struct.unpack("HHHH",fcntl.ioctl(sys.stderr.fileno(),termios.TIOCGWINSZ,struct.pack("HHHH",0,0,0,0)))[:2] - return cols - try: - get_term_cols_real() - except Exception: - pass +indicator='\r\x1b[K%s%s%s' +def enable_colors(use): + if use==1: + if not(sys.stderr.isatty()or sys.stdout.isatty()): + use=0 + if Utils.is_win32: + term=os.environ.get('TERM','') else: - get_term_cols=get_term_cols_real + term=os.environ.get('TERM','dumb') + if term in('dumb','emacs'): + use=0 + if use>=1: + os.environ['TERM']='vt100' + colors_lst['USE']=use +try: + get_term_cols=ansiterm.get_term_cols +except AttributeError: + def get_term_cols(): + return 80 get_term_cols.__doc__=""" Get the console width in characters. @@ -88,16 +54,8 @@ class log_filter(logging.Filter): def __init__(self,name=None): pass def filter(self,rec): - rec.c1=colors.PINK - rec.c2=colors.NORMAL rec.zone=rec.module if rec.levelno>=logging.INFO: - if rec.levelno>=logging.ERROR: - rec.c1=colors.RED - elif rec.levelno>=logging.WARNING: - rec.c1=colors.YELLOW - else: - rec.c1=colors.GREEN return True m=re_log.match(rec.msg) if m: @@ -108,16 +66,70 @@ class log_filter(logging.Filter): elif not verbose>2: return False return True +class log_handler(logging.StreamHandler): + def emit(self,record): + try: + try: + self.stream=record.stream + except AttributeError: + if record.levelno>=logging.WARNING: + record.stream=self.stream=sys.stderr + else: + record.stream=self.stream=sys.stdout + self.emit_override(record) + self.flush() + except(KeyboardInterrupt,SystemExit): + raise + except: + self.handleError(record) + def emit_override(self,record,**kw): + self.terminator=getattr(record,'terminator','\n') + stream=self.stream + if hasattr(types,"UnicodeType"): + msg=self.formatter.format(record) + fs='%s'+self.terminator + try: + if(isinstance(msg,unicode)and getattr(stream,'encoding',None)): + fs=fs.decode(stream.encoding) + try: + stream.write(fs%msg) + except UnicodeEncodeError: + stream.write((fs%msg).encode(stream.encoding)) + else: + stream.write(fs%msg) + except UnicodeError: + stream.write((fs%msg).encode("UTF-8")) + else: + logging.StreamHandler.emit(self,record) class formatter(logging.Formatter): def __init__(self): logging.Formatter.__init__(self,LOG_FORMAT,HOUR_FORMAT) def format(self,rec): - if rec.levelno>=logging.WARNING or rec.levelno==logging.INFO: - try: - msg=rec.msg.decode('utf-8') - except Exception: - msg=rec.msg - return'%s%s%s'%(rec.c1,msg,rec.c2) + try: + msg=rec.msg.decode('utf-8') + except Exception: + msg=rec.msg + use=colors_lst['USE'] + if(use==1 and rec.stream.isatty())or use==2: + c1=getattr(rec,'c1',None) + if c1 is None: + c1='' + if rec.levelno>=logging.ERROR: + c1=colors.RED + elif rec.levelno>=logging.WARNING: + c1=colors.YELLOW + elif rec.levelno>=logging.INFO: + c1=colors.GREEN + c2=getattr(rec,'c2',colors.NORMAL) + msg='%s%s%s'%(c1,msg,c2) + else: + msg=msg.replace('\r','\n') + msg=re.sub(r'\x1B\[(K|.*?(m|h|l))','',msg) + if rec.levelno>=logging.INFO: + return msg + rec.msg=msg + rec.c1=colors.PINK + rec.c2=colors.NORMAL return logging.Formatter.format(self,rec) log=None def debug(*k,**kw): @@ -150,7 +162,7 @@ def init_log(): log=logging.getLogger('waflib') log.handlers=[] log.filters=[] - hdlr=logging.StreamHandler() + hdlr=log_handler() hdlr.setFormatter(formatter()) log.addHandler(hdlr) log.addFilter(log_filter()) @@ -163,7 +175,7 @@ def make_logger(path,name): logger.addHandler(hdlr) logger.setLevel(logging.DEBUG) return logger -def make_mem_logger(name,to_log,size=10000): +def make_mem_logger(name,to_log,size=8192): from logging.handlers import MemoryHandler logger=logging.getLogger(name) hdlr=MemoryHandler(size,target=to_log) @@ -173,5 +185,12 @@ def make_mem_logger(name,to_log,size=10000): logger.memhandler=hdlr logger.setLevel(logging.DEBUG) return logger -def pprint(col,str,label='',sep='\n'): - sys.stderr.write("%s%s%s %s%s"%(colors(col),str,colors.NORMAL,label,sep)) +def free_logger(logger): + try: + for x in logger.handlers: + x.close() + logger.removeHandler(x) + except Exception ,e: + pass +def pprint(col,msg,label='',sep='\n'): + info("%s%s%s %s"%(colors(col),msg,colors.NORMAL,label),extra={'terminator':sep}) diff --git a/waflib/Node.py b/waflib/Node.py index 77296134..09dfb5a9 100644 --- a/waflib/Node.py +++ b/waflib/Node.py @@ -46,15 +46,19 @@ def split_path_cygwin(path): re_sp=re.compile('[/\\\\]') def split_path_win32(path): if path.startswith('\\\\'): - ret=re.split(re_sp,path)[2:] - ret[0]='\\'+ret[0] - return ret + if path.startswith('\\\\?'): + path=path[4:] + else: + ret=re.split(re_sp,path)[2:] + ret[0]='\\\\'+ret[0] + return ret return re.split(re_sp,path) if sys.platform=='cygwin': split_path=split_path_cygwin elif Utils.is_win32: split_path=split_path_win32 class Node(object): + dict_class=dict __slots__=('name','sig','children','parent','cache_abspath','cache_isdir','cache_sig') def __init__(self,name,parent): self.name=name @@ -67,7 +71,7 @@ class Node(object): self.name=data[0] self.parent=data[1] if data[2]is not None: - self.children=data[2] + self.children=self.dict_class(data[2]) if data[3]is not None: self.sig=data[3] def __getstate__(self): @@ -90,13 +94,16 @@ class Node(object): os.chmod(self.abspath(),val) def delete(self): try: - if hasattr(self,'children'): - shutil.rmtree(self.abspath()) - else: - os.remove(self.abspath()) - except OSError: - pass - self.evict() + try: + if hasattr(self,'children'): + shutil.rmtree(self.abspath()) + else: + os.remove(self.abspath()) + except OSError ,e: + if os.path.exists(self.abspath()): + raise e + finally: + self.evict() def evict(self): del self.parent.children[self.name] def suffix(self): @@ -130,7 +137,7 @@ class Node(object): try: self.children except AttributeError: - self.children={} + self.children=self.dict_class() self.cache_isdir=True def find_node(self,lst): if isinstance(lst,str): @@ -143,7 +150,7 @@ class Node(object): try: ch=cur.children except AttributeError: - cur.children={} + cur.children=self.dict_class() else: try: cur=cur.children[x] @@ -182,7 +189,7 @@ class Node(object): cur=cur.children[x] continue else: - cur.children={} + cur.children=self.dict_class() cur=self.__class__(x,cur) return cur def search_node(self,lst): @@ -218,8 +225,12 @@ class Node(object): up+=1 c1=c1.parent c2=c2.parent - for i in range(up): - lst.append('..') + if c1.parent: + for i in range(up): + lst.append('..') + else: + if os.sep=='/'and lst: + lst.append('') lst.reverse() return os.sep.join(lst)or'.' def abspath(self): @@ -256,7 +267,7 @@ class Node(object): try: lst=set(self.children.keys()) except AttributeError: - self.children={} + self.children=self.dict_class() else: if remove: for x in lst-set(dircont): @@ -433,8 +444,6 @@ class Node(object): else: name=name[:-len(ext_in)]+ext return self.parent.find_or_declare([name]) - def nice_path(self,env=None): - return self.path_from(self.ctx.launch_node()) def bldpath(self): return self.path_from(self.ctx.bldnode) def srcpath(self): @@ -449,9 +458,6 @@ class Node(object): return self.srcpath() def bld_dir(self): return self.parent.bldpath() - def bld_base(self): - s=os.path.splitext(self.name)[0] - return self.bld_dir()+os.sep+s def get_bld_sig(self): try: return self.cache_sig @@ -461,7 +467,6 @@ class Node(object): self.sig=Utils.h_file(self.abspath()) self.cache_sig=ret=self.sig return ret - search=search_node pickle_lock=Utils.threading.Lock() class Nod3(Node): pass diff --git a/waflib/Options.py b/waflib/Options.py index 21f42543..926161bf 100644 --- a/waflib/Options.py +++ b/waflib/Options.py @@ -7,58 +7,26 @@ from waflib import Logs,Utils,Context cmds='distclean configure build install clean uninstall check dist distcheck'.split() options={} commands=[] +envvars=[] lockfile=os.environ.get('WAFLOCK','.lock-waf_%s_build'%sys.platform) -try:cache_global=os.path.abspath(os.environ['WAFCACHE']) -except KeyError:cache_global='' platform=Utils.unversioned_sys_platform() class opt_parser(optparse.OptionParser): def __init__(self,ctx): optparse.OptionParser.__init__(self,conflict_handler="resolve",version='waf %s (%s)'%(Context.WAFVERSION,Context.WAFREVISION)) self.formatter.width=Logs.get_term_cols() - p=self.add_option self.ctx=ctx - jobs=ctx.jobs() - p('-j','--jobs',dest='jobs',default=jobs,type='int',help='amount of parallel jobs (%r)'%jobs) - p('-k','--keep',dest='keep',default=0,action='count',help='keep running happily even if errors are found') - p('-v','--verbose',dest='verbose',default=0,action='count',help='verbosity level -v -vv or -vvv [default: 0]') - p('--nocache',dest='nocache',default=False,action='store_true',help='ignore the WAFCACHE (if set)') - p('--zones',dest='zones',default='',action='store',help='debugging zones (task_gen, deps, tasks, etc)') - gr=optparse.OptionGroup(self,'configure options') - self.add_option_group(gr) - gr.add_option('-o','--out',action='store',default='',help='build dir for the project',dest='out') - gr.add_option('-t','--top',action='store',default='',help='src dir for the project',dest='top') - default_prefix=os.environ.get('PREFIX') - if not default_prefix: - if platform=='win32': - d=tempfile.gettempdir() - default_prefix=d[0].upper()+d[1:] - else: - default_prefix='/usr/local/' - gr.add_option('--prefix',dest='prefix',default=default_prefix,help='installation prefix [default: %r]'%default_prefix) - gr.add_option('--download',dest='download',default=False,action='store_true',help='try to download the tools if missing') - gr=optparse.OptionGroup(self,'build and install options') - self.add_option_group(gr) - gr.add_option('-p','--progress',dest='progress_bar',default=0,action='count',help='-p: progress bar; -pp: ide output') - gr.add_option('--targets',dest='targets',default='',action='store',help='task generators, e.g. "target1,target2"') - gr=optparse.OptionGroup(self,'step options') - self.add_option_group(gr) - gr.add_option('--files',dest='files',default='',action='store',help='files to process, by regexp, e.g. "*/main.c,*/test/main.o"') - default_destdir=os.environ.get('DESTDIR','') - gr=optparse.OptionGroup(self,'install/uninstall options') - self.add_option_group(gr) - gr.add_option('--destdir',help='installation root [default: %r]'%default_destdir,default=default_destdir,dest='destdir') - gr.add_option('-f','--force',dest='force',default=False,action='store_true',help='force file installation') - gr.add_option('--distcheck-args',help='arguments to pass to distcheck',default=None,action='store') + def print_usage(self,file=None): + return self.print_help(file) def get_usage(self): cmds_str={} for cls in Context.classes: - if not cls.cmd or cls.cmd=='options': + if not cls.cmd or cls.cmd=='options'or cls.cmd.startswith('_'): continue s=cls.__doc__ or'' cmds_str[cls.cmd]=s if Context.g_module: for(k,v)in Context.g_module.__dict__.items(): - if k in['options','init','shutdown']: + if k in('options','init','shutdown'): continue if type(v)is type(Context.create_context): if v.__doc__ and not k.startswith('_'): @@ -81,6 +49,41 @@ class OptionsContext(Context.Context): super(OptionsContext,self).__init__(**kw) self.parser=opt_parser(self) self.option_groups={} + jobs=self.jobs() + p=self.add_option + color=os.environ.get('NOCOLOR','')and'no'or'auto' + p('-c','--color',dest='colors',default=color,action='store',help='whether to use colors (yes/no/auto) [default: auto]',choices=('yes','no','auto')) + p('-j','--jobs',dest='jobs',default=jobs,type='int',help='amount of parallel jobs (%r)'%jobs) + p('-k','--keep',dest='keep',default=0,action='count',help='continue despite errors (-kk to try harder)') + p('-v','--verbose',dest='verbose',default=0,action='count',help='verbosity level -v -vv or -vvv [default: 0]') + p('--zones',dest='zones',default='',action='store',help='debugging zones (task_gen, deps, tasks, etc)') + gr=self.add_option_group('Configuration options') + self.option_groups['configure options']=gr + gr.add_option('-o','--out',action='store',default='',help='build dir for the project',dest='out') + gr.add_option('-t','--top',action='store',default='',help='src dir for the project',dest='top') + default_prefix=getattr(Context.g_module,'default_prefix',os.environ.get('PREFIX')) + if not default_prefix: + if platform=='win32': + d=tempfile.gettempdir() + default_prefix=d[0].upper()+d[1:] + else: + default_prefix='/usr/local/' + gr.add_option('--prefix',dest='prefix',default=default_prefix,help='installation prefix [default: %r]'%default_prefix) + gr.add_option('--bindir',dest='bindir',help='bindir') + gr.add_option('--libdir',dest='libdir',help='libdir') + gr=self.add_option_group('Build and installation options') + self.option_groups['build and install options']=gr + gr.add_option('-p','--progress',dest='progress_bar',default=0,action='count',help='-p: progress bar; -pp: ide output') + gr.add_option('--targets',dest='targets',default='',action='store',help='task generators, e.g. "target1,target2"') + gr=self.add_option_group('Step options') + self.option_groups['step options']=gr + gr.add_option('--files',dest='files',default='',action='store',help='files to process, by regexp, e.g. "*/main.c,*/test/main.o"') + default_destdir=os.environ.get('DESTDIR','') + gr=self.add_option_group('Installation and uninstallation options') + self.option_groups['install/uninstall options']=gr + gr.add_option('--destdir',help='installation root [default: %r]'%default_destdir,default=default_destdir,dest='destdir') + gr.add_option('-f','--force',dest='force',default=False,action='store_true',help='force file installation') + gr.add_option('--distcheck-args',metavar='ARGS',help='arguments to pass to distcheck',default=None,action='store') def jobs(self): count=int(os.environ.get('JOBS',0)) if count<1: @@ -123,13 +126,19 @@ class OptionsContext(Context.Context): return group return None def parse_args(self,_args=None): - global options,commands + global options,commands,envvars (options,leftover_args)=self.parser.parse_args(args=_args) - commands=leftover_args + for arg in leftover_args: + if'='in arg: + envvars.append(arg) + else: + commands.append(arg) if options.destdir: options.destdir=os.path.abspath(os.path.expanduser(options.destdir)) if options.verbose>=1: self.load('errcheck') + colors={'yes':2,'auto':1,'no':0}[options.colors] + Logs.enable_colors(colors) def execute(self): super(OptionsContext,self).execute() self.parse_args() diff --git a/waflib/Runner.py b/waflib/Runner.py index 15b6a27b..7b292651 100644 --- a/waflib/Runner.py +++ b/waflib/Runner.py @@ -109,10 +109,6 @@ class Parallel(object): self.count-=1 self.dirty=True return tsk - def error_handler(self,tsk): - if not self.bld.keep: - self.stop=True - self.error.append(tsk) def add_task(self,tsk): try: self.pool @@ -143,6 +139,31 @@ class Parallel(object): for x in pool: put_pool(x) self.pool=[] + def skip(self,tsk): + tsk.hasrun=Task.SKIPPED + def error_handler(self,tsk): + if not self.bld.keep: + self.stop=True + self.error.append(tsk) + def task_status(self,tsk): + try: + return tsk.runnable_status() + except Exception: + self.processed+=1 + tsk.err_msg=Utils.ex_stack() + if not self.stop and self.bld.keep: + self.skip(tsk) + if self.bld.keep==1: + if Logs.verbose>1 or not self.error: + self.error.append(tsk) + self.stop=True + else: + if Logs.verbose>1: + self.error.append(tsk) + return Task.EXCEPTION + tsk.hasrun=Task.EXCEPTION + self.error_handler(tsk) + return Task.EXCEPTION def start(self): self.total=self.bld.total() while not self.stop: @@ -158,31 +179,8 @@ class Parallel(object): continue if self.stop: break - try: - st=tsk.runnable_status() - except Exception: - self.processed+=1 - tsk.err_msg=Utils.ex_stack() - if not self.stop and self.bld.keep: - tsk.hasrun=Task.SKIPPED - if self.bld.keep==1: - if Logs.verbose>1 or not self.error: - self.error.append(tsk) - self.stop=True - else: - if Logs.verbose>1: - self.error.append(tsk) - continue - tsk.hasrun=Task.EXCEPTION - self.error_handler(tsk) - continue - if st==Task.ASK_LATER: - self.postpone(tsk) - elif st==Task.SKIP_ME: - self.processed+=1 - tsk.hasrun=Task.SKIPPED - self.add_more_tasks(tsk) - else: + st=self.task_status(tsk) + if st==Task.RUN_ME: tsk.position=(self.processed,self.total) self.count+=1 tsk.master=self @@ -191,6 +189,12 @@ class Parallel(object): tsk.process() else: self.add_task(tsk) + if st==Task.ASK_LATER: + self.postpone(tsk) + elif st==Task.SKIP_ME: + self.processed+=1 + self.skip(tsk) + self.add_more_tasks(tsk) while self.error and self.count: self.get_out() assert(self.count==0 or self.stop) diff --git a/waflib/Scripting.py b/waflib/Scripting.py index aec71243..54d191a0 100644 --- a/waflib/Scripting.py +++ b/waflib/Scripting.py @@ -18,14 +18,20 @@ def waf_entry_point(current_directory,version,wafdir): ctx.curdir=current_directory ctx.parse_args() sys.exit(0) + if len(sys.argv)>1: + potential_wscript=os.path.join(current_directory,sys.argv[1]) + if os.path.basename(potential_wscript)=='wscript'and os.path.isfile(potential_wscript): + current_directory=os.path.normpath(os.path.dirname(potential_wscript)) + sys.argv.pop(1) Context.waf_dir=wafdir Context.launch_dir=current_directory no_climb=os.environ.get('NOCLIMB',None) if not no_climb: for k in no_climb_commands: - if k in sys.argv: - no_climb=True - break + for y in sys.argv: + if y.startswith(k): + no_climb=True + break cur=current_directory while cur: lst=os.listdir(cur) @@ -37,7 +43,7 @@ def waf_entry_point(current_directory,version,wafdir): except Exception: pass else: - for x in[env.run_dir,env.top_dir,env.out_dir]: + for x in(env.run_dir,env.top_dir,env.out_dir): if Utils.is_win32: if cur==x: load=True @@ -84,7 +90,7 @@ def waf_entry_point(current_directory,version,wafdir): Logs.error('Waf: The folder %r is unreadable'%Context.run_dir) sys.exit(1) try: - set_main_module(Context.run_dir+os.sep+Context.WSCRIPT_FILE) + set_main_module(os.path.join(Context.run_dir,Context.WSCRIPT_FILE)) except Errors.WafError ,e: Logs.pprint('RED',e.verbose_msg) Logs.error(str(e)) @@ -115,7 +121,7 @@ def set_main_module(file_path): name=obj.__name__ if not name in Context.g_module.__dict__: setattr(Context.g_module,name,obj) - for k in[update,dist,distclean,distcheck,update]: + for k in(update,dist,distclean,distcheck,update): set_def(k) if not'init'in Context.g_module.__dict__: Context.g_module.init=Utils.nada @@ -125,11 +131,13 @@ def set_main_module(file_path): Context.g_module.options=Utils.nada def parse_options(): Context.create_context('options').execute() + for var in Options.envvars: + (name,value)=var.split('=',1) + os.environ[name.strip()]=value if not Options.commands: Options.commands=[default_cmd] Options.commands=[x for x in Options.commands if x!='options'] Logs.verbose=Options.options.verbose - Logs.init_log() if Options.options.zones: Logs.zones=Options.options.zones.split(',') if not Logs.verbose: @@ -143,7 +151,10 @@ def run_command(cmd_name): ctx.log_timer=Utils.Timer() ctx.options=Options.options ctx.cmd=cmd_name - ctx.execute() + try: + ctx.execute() + finally: + ctx.finalize() return ctx def run_commands(): parse_options() @@ -162,12 +173,12 @@ def distclean_dir(dirname): for(root,dirs,files)in os.walk(dirname): for f in files: if _can_distclean(f): - fname=root+os.sep+f + fname=os.path.join(root,f) try: os.remove(fname) except OSError: Logs.warn('Could not remove %r'%fname) - for x in[Context.DBFILE,'config.log']: + for x in(Context.DBFILE,'config.log'): try: os.remove(x) except OSError: @@ -193,15 +204,16 @@ def distclean(ctx): pass except OSError ,e: if e.errno!=errno.ENOENT: - Logs.warn('project %r cannot be removed'%proj[Context.OUT]) + Logs.warn('Could not remove %r'%proj['out_dir']) else: distclean_dir(proj['out_dir']) for k in(proj['out_dir'],proj['top_dir'],proj['run_dir']): + p=os.path.join(k,Options.lockfile) try: - os.remove(os.path.join(k,Options.lockfile)) + os.remove(p) except OSError ,e: if e.errno!=errno.ENOENT: - Logs.warn('file %r cannot be removed'%f) + Logs.warn('Could not remove %r'%p) if not Options.commands: for x in'.waf-1. waf-1. .waf3-1. waf3-1.'.split(): if f.startswith(x): @@ -225,7 +237,7 @@ class Dist(Context.Context): node=self.base_path.make_node(arch_name) try: node.delete() - except Exception: + except OSError: pass files=self.get_files() if self.algo.startswith('tar.'): @@ -241,7 +253,7 @@ class Dist(Context.Context): zip.write(x.abspath(),archive_name,zipfile.ZIP_DEFLATED) zip.close() else: - self.fatal('Valid algo types are tar.bz2, tar.gz or zip') + self.fatal('Valid algo types are tar.bz2, tar.gz, tar.xz or zip') try: from hashlib import sha1 as sha except ImportError: @@ -290,10 +302,11 @@ class Dist(Context.Context): try: return self.excl except AttributeError: - self.excl=Node.exclude_regs+' **/waf-1.7.* **/.waf-1.7* **/waf3-1.7.* **/.waf3-1.7* **/*~ **/*.rej **/*.orig **/*.pyc **/*.pyo **/*.bak **/*.swp **/.lock-w*' - nd=self.root.find_node(Context.out_dir) - if nd: - self.excl+=' '+nd.path_from(self.base_path) + self.excl=Node.exclude_regs+' **/waf-1.8.* **/.waf-1.8* **/waf3-1.8.* **/.waf3-1.8* **/*~ **/*.rej **/*.orig **/*.pyc **/*.pyo **/*.bak **/*.swp **/.lock-w*' + if Context.out_dir: + nd=self.root.find_node(Context.out_dir) + if nd: + self.excl+=' '+nd.path_from(self.base_path) return self.excl def get_files(self): try: @@ -369,6 +382,8 @@ def autoconfigure(execute_method): if do_config: Options.commands.insert(0,self.cmd) Options.commands.insert(0,'configure') + if Configure.autoconfig=='clobber': + Options.options.__dict__=env.options return return execute_method(self) return execute diff --git a/waflib/Task.py b/waflib/Task.py index 8cc4cc32..3aa44894 100644 --- a/waflib/Task.py +++ b/waflib/Task.py @@ -2,7 +2,7 @@ # encoding: utf-8 # WARNING! Do not edit! http://waf.googlecode.com/git/docs/wafbook/single.html#_obtaining_the_waf_file -import os,shutil,re,tempfile +import os,re,sys from waflib import Utils,Logs,Errors NOT_RUN=0 MISSING=1 @@ -37,24 +37,6 @@ def f(tsk): lst = [x for x in lst if x] return tsk.exec_command(lst, cwd=wd, env=env.env or None) ''' -def cache_outputs(cls): - m1=cls.run - def run(self): - bld=self.generator.bld - if bld.cache_global and not bld.nocache: - if self.can_retrieve_cache(): - return 0 - return m1(self) - cls.run=run - m2=cls.post_run - def post_run(self): - bld=self.generator.bld - ret=m2(self) - if bld.cache_global and not bld.nocache: - self.put_files_cache() - return ret - cls.post_run=post_run - return cls classes={} class store_task_type(type): def __init__(cls,name,bases,dict): @@ -67,14 +49,15 @@ class store_task_type(type): if getattr(cls,'run_str',None): (f,dvars)=compile_fun(cls.run_str,cls.shell) cls.hcode=cls.run_str + cls.orig_run_str=cls.run_str cls.run_str=None cls.run=f cls.vars=list(set(cls.vars+dvars)) cls.vars.sort() elif getattr(cls,'run',None)and not'hcode'in cls.__dict__: cls.hcode=Utils.h_fun(cls.run) - if not getattr(cls,'nocache',None): - cls=cache_outputs(cls) + if sys.hexversion>0x3000000: + cls.hcode=cls.hcode.encode('iso8859-1','xmlcharrefreplace') getattr(cls,'register',classes)[name]=cls evil=store_task_type('evil',(object,),{}) class TaskBase(evil): @@ -94,10 +77,14 @@ class TaskBase(evil): return'\n\t{task %r: %s %s}'%(self.__class__.__name__,id(self),str(getattr(self,'fun',''))) def __str__(self): if hasattr(self,'fun'): - return'executing: %s\n'%self.fun.__name__ - return self.__class__.__name__+'\n' + return self.fun.__name__ + return self.__class__.__name__ def __hash__(self): return id(self) + def keyword(self): + if hasattr(self,'fun'): + return'Function' + return'Processing' def exec_command(self,cmd,**kw): bld=self.generator.bld try: @@ -150,7 +137,20 @@ class TaskBase(evil): def post_run(self): pass def log_display(self,bld): - bld.to_log(self.display()) + if self.generator.bld.progress_bar==3: + return + s=self.display() + if s: + if bld.logger: + logger=bld.logger + else: + logger=Logs + if self.generator.bld.progress_bar==1: + c1=Logs.colors.cursor_off + c2=Logs.colors.cursor_on + logger.info(s,extra={'stream':sys.stderr,'terminator':'','c1':c1,'c2':c2}) + else: + logger.info(s,extra={'terminator':'','c1':'','c2':''}) def display(self): col1=Logs.colors(self.color) col2=Logs.colors.NORMAL @@ -178,8 +178,11 @@ class TaskBase(evil): return None total=master.total n=len(str(total)) - fs='[%%%dd/%%%dd] %%s%%s%%s'%(n,n) - return fs%(cur(),total,col1,s,col2) + fs='[%%%dd/%%%dd] %%s%%s%%s%%s\n'%(n,n) + kw=self.keyword() + if kw: + kw+=' ' + return fs%(cur(),total,kw,col1,s,col2) def attr(self,att,default=None): ret=getattr(self,att,self) if ret is self:return getattr(self.__class__,att,default) @@ -207,6 +210,8 @@ class TaskBase(evil): return'invalid status for task in %r: %r'%(name,self.hasrun) def colon(self,var1,var2): tmp=self.env[var1] + if not tmp: + return[] if isinstance(var2,str): it=self.env[var2] else: @@ -214,8 +219,6 @@ class TaskBase(evil): if isinstance(tmp,str): return[tmp%x for x in it] else: - if Logs.verbose and not tmp and it: - Logs.warn('Missing env variable %r for task %r (generator %r)'%(var1,self,self.generator)) lst=[] for y in it: lst.extend(tmp) @@ -232,12 +235,33 @@ class Task(TaskBase): self.dep_nodes=[] self.run_after=set([]) def __str__(self): - env=self.env - src_str=' '.join([a.nice_path()for a in self.inputs]) - tgt_str=' '.join([a.nice_path()for a in self.outputs]) + name=self.__class__.__name__ + if self.outputs: + if(name.endswith('lib')or name.endswith('program'))or not self.inputs: + node=self.outputs[0] + return node.path_from(node.ctx.launch_node()) + if not(self.inputs or self.outputs): + return self.__class__.__name__ + if len(self.inputs)==1: + node=self.inputs[0] + return node.path_from(node.ctx.launch_node()) + src_str=' '.join([a.path_from(a.ctx.launch_node())for a in self.inputs]) + tgt_str=' '.join([a.path_from(a.ctx.launch_node())for a in self.outputs]) if self.outputs:sep=' -> ' else:sep='' - return'%s: %s%s%s\n'%(self.__class__.__name__.replace('_task',''),src_str,sep,tgt_str) + return'%s: %s%s%s'%(self.__class__.__name__.replace('_task',''),src_str,sep,tgt_str) + def keyword(self): + name=self.__class__.__name__ + if name.endswith('lib')or name.endswith('program'): + return'Linking' + if len(self.inputs)==1 and len(self.outputs)==1: + return'Compiling' + if not self.inputs: + if self.outputs: + return'Creating' + else: + return'Running' + return'Processing' def __repr__(self): try: ins=",".join([x.name for x in self.inputs]) @@ -361,9 +385,11 @@ class Task(TaskBase): try: if prev==self.compute_sig_implicit_deps(): return prev - except Exception: + except Errors.TaskNotReady: + raise + except EnvironmentError: for x in bld.node_deps.get(self.uid(),[]): - if x.is_child_of(bld.srcnode): + if not x.is_bld(): try: os.stat(x.abspath()) except OSError: @@ -419,71 +445,20 @@ class Task(TaskBase): for tsk in self.run_after: if not tsk.hasrun: raise Errors.TaskNotReady('not ready') - def can_retrieve_cache(self): - if not getattr(self,'outputs',None): - return None - sig=self.signature() - ssig=Utils.to_hex(self.uid())+Utils.to_hex(sig) - dname=os.path.join(self.generator.bld.cache_global,ssig) - try: - t1=os.stat(dname).st_mtime - except OSError: - return None - for node in self.outputs: - orig=os.path.join(dname,node.name) - try: - shutil.copy2(orig,node.abspath()) - os.utime(orig,None) - except(OSError,IOError): - Logs.debug('task: failed retrieving file') - return None - try: - t2=os.stat(dname).st_mtime - except OSError: - return None - if t1!=t2: - return None - for node in self.outputs: - node.sig=sig - if self.generator.bld.progress_bar<1: - self.generator.bld.to_log('restoring from cache %r\n'%node.abspath()) - self.cached=True - return True - def put_files_cache(self): - if getattr(self,'cached',None): - return None - if not getattr(self,'outputs',None): - return None - sig=self.signature() - ssig=Utils.to_hex(self.uid())+Utils.to_hex(sig) - dname=os.path.join(self.generator.bld.cache_global,ssig) - tmpdir=tempfile.mkdtemp(prefix=self.generator.bld.cache_global+os.sep+'waf') - try: - shutil.rmtree(dname) - except Exception: - pass +if sys.hexversion>0x3000000: + def uid(self): try: - for node in self.outputs: - dest=os.path.join(tmpdir,node.name) - shutil.copy2(node.abspath(),dest) - except(OSError,IOError): - try: - shutil.rmtree(tmpdir) - except Exception: - pass - else: - try: - os.rename(tmpdir,dname) - except OSError: - try: - shutil.rmtree(tmpdir) - except Exception: - pass - else: - try: - os.chmod(dname,Utils.O755) - except Exception: - pass + return self.uid_ + except AttributeError: + m=Utils.md5() + up=m.update + up(self.__class__.__name__.encode('iso8859-1','xmlcharrefreplace')) + for x in self.inputs+self.outputs: + up(x.abspath().encode('iso8859-1','xmlcharrefreplace')) + self.uid_=m.digest() + return self.uid_ + uid.__doc__=Task.uid.__doc__ + Task.uid=uid def is_before(t1,t2): to_list=Utils.to_list for k in to_list(t2.ext_in): @@ -578,6 +553,7 @@ def compile_fun_noshell(line): def repl(match): g=match.group if g('dollar'):return"$" + elif g('backslash'):return'\\' elif g('subst'):extr.append((g('var'),g('code')));return"<<|@|>>" return None line2=reg_act.sub(repl,line) diff --git a/waflib/TaskGen.py b/waflib/TaskGen.py index 381bfce4..e34b8be5 100644 --- a/waflib/TaskGen.py +++ b/waflib/TaskGen.py @@ -5,8 +5,9 @@ import copy,re,os from waflib import Task,Utils,Logs,Errors,ConfigSet,Node feats=Utils.defaultdict(set) +HEADER_EXTS=['.h','.hpp','.hxx','.hh'] class task_gen(object): - mappings={} + mappings=Utils.ordered_iter_dict() prec=Utils.defaultdict(list) def __init__(self,*k,**kw): self.source='' @@ -36,7 +37,7 @@ class task_gen(object): def __repr__(self): lst=[] for x in self.__dict__.keys(): - if x not in['env','bld','compiled_tasks','tasks']: + if x not in('env','bld','compiled_tasks','tasks'): lst.append("%s=%s"%(x,repr(getattr(self,x)))) return"bld(%s) in %s"%(", ".join(lst),self.path.abspath()) def get_name(self): @@ -111,27 +112,29 @@ class task_gen(object): return True def get_hook(self,node): name=node.name - for k in self.mappings: - if name.endswith(k): - return self.mappings[k] + if self.mappings: + for k in self.mappings: + if name.endswith(k): + return self.mappings[k] for k in task_gen.mappings: if name.endswith(k): return task_gen.mappings[k] - raise Errors.WafError("File %r has no mapping in %r (did you forget to load a waf tool?)"%(node,task_gen.mappings.keys())) - def create_task(self,name,src=None,tgt=None): + raise Errors.WafError("File %r has no mapping in %r (have you forgotten to load a waf tool?)"%(node,task_gen.mappings.keys())) + def create_task(self,name,src=None,tgt=None,**kw): task=Task.classes[name](env=self.env.derive(),generator=self) if src: task.set_inputs(src) if tgt: task.set_outputs(tgt) + task.__dict__.update(kw) self.tasks.append(task) return task def clone(self,env): newobj=self.bld() for x in self.__dict__: - if x in['env','bld']: + if x in('env','bld'): continue - elif x in['path','features']: + elif x in('path','features'): setattr(newobj,x,getattr(self,x)) else: setattr(newobj,x,copy.copy(getattr(self,x))) @@ -153,7 +156,7 @@ def declare_chain(name='',rule=None,reentrant=None,color='BLUE',ext_in=[],ext_ou _ext_in=ext_in[0] tsk=self.create_task(name,node) cnt=0 - keys=list(self.mappings.keys())+list(self.__class__.mappings.keys()) + keys=set(self.mappings.keys())|set(self.__class__.mappings.keys()) for x in ext: k=node.change_ext(x,ext_in=_ext_in) tsk.outputs.append(k) @@ -212,7 +215,7 @@ def to_nodes(self,lst,path=None): tmp=[] path=path or self.path find=path.find_resource - if isinstance(lst,self.path.__class__): + if isinstance(lst,Node.Node): lst=[lst] for x in Utils.to_list(lst): if isinstance(x,str): @@ -262,7 +265,7 @@ def process_rule(self): Task.update_outputs(cls) if getattr(self,'always',None): Task.always_run(cls) - for x in['after','before','ext_in','ext_out']: + for x in('after','before','ext_in','ext_out'): setattr(cls,x,getattr(self,x,[])) if getattr(self,'cache_rule','True'): cache[(name,self.rule)]=cls @@ -307,11 +310,11 @@ class subst_pc(Task.Task): os.chmod(self.outputs[0].abspath(),self.generator.chmod) return None if getattr(self.generator,'fun',None): - self.generator.fun(self) + return self.generator.fun(self) code=self.inputs[0].read(encoding=getattr(self.generator,'encoding','ISO8859-1')) if getattr(self.generator,'subst_fun',None): code=self.generator.subst_fun(self,code) - if code: + if code is not None: self.outputs[0].write(code,encoding=getattr(self.generator,'encoding','ISO8859-1')) return code=code.replace('%','%%') @@ -329,8 +332,12 @@ class subst_pc(Task.Task): except AttributeError: d={} for x in lst: - tmp=getattr(self.generator,x,'')or self.env.get_flat(x)or self.env.get_flat(x.upper()) - d[x]=str(tmp) + tmp=getattr(self.generator,x,'')or self.env[x]or self.env[x.upper()] + try: + tmp=''.join(tmp) + except TypeError: + tmp=str(tmp) + d[x]=tmp code=code%d self.outputs[0].write(code,encoding=getattr(self.generator,'encoding','ISO8859-1')) self.generator.bld.raw_deps[self.uid()]=self.dep_vars=lst @@ -397,8 +404,12 @@ def process_subst(self): if val: has_constraints=True setattr(tsk,k,val) - if not has_constraints and b.name.endswith('.h'): - tsk.before=[k for k in('c','cxx')if k in Task.classes] + if not has_constraints: + global HEADER_EXTS + for xt in HEADER_EXTS: + if b.name.endswith(xt): + tsk.before=[k for k in('c','cxx')if k in Task.classes] + break inst_to=getattr(self,'install_path',None) if inst_to: self.bld.install_files(inst_to,b,chmod=getattr(self,'chmod',Utils.O644)) diff --git a/waflib/Tools/ar.py b/waflib/Tools/ar.py index 7a16dfed..9488ead1 100644 --- a/waflib/Tools/ar.py +++ b/waflib/Tools/ar.py @@ -8,4 +8,6 @@ def find_ar(conf): conf.load('ar') def configure(conf): conf.find_program('ar',var='AR') - conf.env.ARFLAGS='rcs' + conf.add_os_flags('ARFLAGS') + if not conf.env.ARFLAGS: + conf.env.ARFLAGS=['rcs'] diff --git a/waflib/Tools/asm.py b/waflib/Tools/asm.py index b9ed5f4b..c1991fd3 100644 --- a/waflib/Tools/asm.py +++ b/waflib/Tools/asm.py @@ -9,7 +9,7 @@ from waflib.Tools.ccroot import link_task,stlink_task from waflib.TaskGen import extension,feature class asm(Task.Task): color='BLUE' - run_str='${AS} ${ASFLAGS} ${ASMPATH_ST:INCPATHS} ${AS_SRC_F}${SRC} ${AS_TGT_F}${TGT}' + run_str='${AS} ${ASFLAGS} ${ASMPATH_ST:INCPATHS} ${DEFINES_ST:DEFINES} ${AS_SRC_F}${SRC} ${AS_TGT_F}${TGT}' @extension('.s','.S','.asm','.ASM','.spp','.SPP') def asm_hook(self,node): return self.create_compiled_task('asm',node) diff --git a/waflib/Tools/c.py b/waflib/Tools/c.py index 4d8cbd55..2252e5e0 100644 --- a/waflib/Tools/c.py +++ b/waflib/Tools/c.py @@ -7,9 +7,11 @@ from waflib.Tools import c_preproc from waflib.Tools.ccroot import link_task,stlink_task @TaskGen.extension('.c') def c_hook(self,node): + if not self.env.CC and self.env.CXX: + return self.create_compiled_task('cxx',node) return self.create_compiled_task('c',node) class c(Task.Task): - run_str='${CC} ${ARCH_ST:ARCH} ${CFLAGS} ${CPPFLAGS} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ${CPPPATH_ST:INCPATHS} ${DEFINES_ST:DEFINES} ${CC_SRC_F}${SRC} ${CC_TGT_F}${TGT}' + run_str='${CC} ${ARCH_ST:ARCH} ${CFLAGS} ${CPPFLAGS} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ${CPPPATH_ST:INCPATHS} ${DEFINES_ST:DEFINES} ${CC_SRC_F}${SRC} ${CC_TGT_F}${TGT[0].abspath()}' vars=['CCDEPS'] ext_in=['.h'] scan=c_preproc.scan diff --git a/waflib/Tools/c_aliases.py b/waflib/Tools/c_aliases.py index a3a2bb90..34e1a9a8 100644 --- a/waflib/Tools/c_aliases.py +++ b/waflib/Tools/c_aliases.py @@ -29,9 +29,9 @@ def sniff_features(**kw): feats.append('java') if'java'in exts: return'java' - if type in['program','shlib','stlib']: + if type in('program','shlib','stlib'): for x in feats: - if x in['cxx','d','c']: + if x in('cxx','d','c'): feats.append(x+type) return feats def set_features(kw,_type): diff --git a/waflib/Tools/c_config.py b/waflib/Tools/c_config.py index eb615d82..3282122f 100755 --- a/waflib/Tools/c_config.py +++ b/waflib/Tools/c_config.py @@ -43,15 +43,19 @@ int main(int argc, char **argv) { MACRO_TO_DESTOS={'__linux__':'linux','__GNU__':'gnu','__FreeBSD__':'freebsd','__NetBSD__':'netbsd','__OpenBSD__':'openbsd','__sun':'sunos','__hpux':'hpux','__sgi':'irix','_AIX':'aix','__CYGWIN__':'cygwin','__MSYS__':'msys','_UWIN':'uwin','_WIN64':'win32','_WIN32':'win32','__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__':'darwin','__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__':'darwin','__QNX__':'qnx','__native_client__':'nacl'} MACRO_TO_DEST_CPU={'__x86_64__':'x86_64','__amd64__':'x86_64','__i386__':'x86','__ia64__':'ia','__mips__':'mips','__sparc__':'sparc','__alpha__':'alpha','__aarch64__':'aarch64','__thumb__':'thumb','__arm__':'arm','__hppa__':'hppa','__powerpc__':'powerpc','__ppc__':'powerpc','__convex__':'convex','__m68k__':'m68k','__s390x__':'s390x','__s390__':'s390','__sh__':'sh',} @conf -def parse_flags(self,line,uselib_store,env=None,force_static=False): +def parse_flags(self,line,uselib_store,env=None,force_static=False,posix=None): assert(isinstance(line,str)) env=env or self.env - app=env.append_value - appu=env.append_unique - lex=shlex.shlex(line,posix=False) + if posix is None: + posix=True + if'\\'in line: + posix=('\\ 'in line)or('\\\\'in line) + lex=shlex.shlex(line,posix=posix) lex.whitespace_split=True lex.commenters='' lst=list(lex) + app=env.append_value + appu=env.append_unique uselib=uselib_store while lst: x=lst.pop(0) @@ -60,7 +64,7 @@ def parse_flags(self,line,uselib_store,env=None,force_static=False): if st=='-I'or st=='/I': if not ot:ot=lst.pop(0) appu('INCLUDES_'+uselib,[ot]) - elif st=='-include': + elif st=='-i': tmp=[x,lst.pop(0)] app('CFLAGS',tmp) app('CXXFLAGS',tmp) @@ -84,6 +88,12 @@ def parse_flags(self,line,uselib_store,env=None,force_static=False): appu('FRAMEWORK_'+uselib,[lst.pop(0)]) elif x.startswith('-F'): appu('FRAMEWORKPATH_'+uselib,[x[2:]]) + elif x=='-Wl,-rpath': + app('RPATH_'+uselib,lst.pop(0)) + elif x.startswith('-Wl,-R'): + app('RPATH_'+uselib,x[6:]) + elif x.startswith('-Wl,-rpath,'): + app('RPATH_'+uselib,x[11:]) elif x.startswith('-Wl'): app('LINKFLAGS_'+uselib,[x]) elif x.startswith('-m')or x.startswith('-f')or x.startswith('-dynamic'): @@ -91,7 +101,7 @@ def parse_flags(self,line,uselib_store,env=None,force_static=False): app('CXXFLAGS_'+uselib,[x]) elif x.startswith('-bundle'): app('LINKFLAGS_'+uselib,[x]) - elif x.startswith('-undefined'): + elif x.startswith('-undefined')or x.startswith('-Xlinker'): arg=lst.pop(0) app('LINKFLAGS_'+uselib,[x,arg]) elif x.startswith('-arch')or x.startswith('-isysroot'): @@ -102,11 +112,6 @@ def parse_flags(self,line,uselib_store,env=None,force_static=False): elif x.endswith('.a')or x.endswith('.so')or x.endswith('.dylib')or x.endswith('.lib'): appu('LINKFLAGS_'+uselib,[x]) @conf -def ret_msg(self,f,kw): - if isinstance(f,str): - return f - return f(kw) -@conf def validate_cfg(self,kw): if not'path'in kw: if not self.env.PKGCONFIG: @@ -132,14 +137,25 @@ def validate_cfg(self,kw): if not'msg'in kw: kw['msg']='Checking for %r %s %s'%(kw['package'],cfg_ver[x],kw[y]) return + if not'define_name'in kw: + pkgname=kw.get('uselib_store',kw['package'].upper()) + kw['define_name']=self.have_define(pkgname) + if not'uselib_store'in kw: + self.undefine(kw['define_name']) if not'msg'in kw: kw['msg']='Checking for %r'%(kw['package']or kw['path']) @conf def exec_cfg(self,kw): + path=Utils.to_list(kw['path']) def define_it(): - self.define(self.have_define(kw.get('uselib_store',kw['package'])),1,0) + pkgname=kw.get('uselib_store',kw['package'].upper()) + if kw.get('global_define'): + self.define(self.have_define(kw['package']),1,False) + else: + self.env.append_unique('DEFINES_%s'%pkgname,"%s=1"%self.have_define(pkgname)) + self.env[self.have_define(pkgname)]=1 if'atleast_pkgconfig_version'in kw: - cmd=[kw['path'],'--atleast-pkgconfig-version=%s'%kw['atleast_pkgconfig_version']] + cmd=path+['--atleast-pkgconfig-version=%s'%kw['atleast_pkgconfig_version']] self.cmd_and_log(cmd) if not'okmsg'in kw: kw['okmsg']='yes' @@ -147,22 +163,22 @@ def exec_cfg(self,kw): for x in cfg_ver: y=x.replace('-','_') if y in kw: - self.cmd_and_log([kw['path'],'--%s=%s'%(x,kw[y]),kw['package']]) + self.cmd_and_log(path+['--%s=%s'%(x,kw[y]),kw['package']]) if not'okmsg'in kw: kw['okmsg']='yes' define_it() break if'modversion'in kw: - version=self.cmd_and_log([kw['path'],'--modversion',kw['modversion']]).strip() + version=self.cmd_and_log(path+['--modversion',kw['modversion']]).strip() self.define('%s_VERSION'%Utils.quote_define_name(kw.get('uselib_store',kw['modversion'])),version) return version - lst=[kw['path']] + lst=[]+path defi=kw.get('define_variable',None) if not defi: defi=self.env.PKG_CONFIG_DEFINES or{} for key,val in defi.items(): lst.append('--define-variable=%s=%s'%(key,val)) - static=False + static=kw.get('force_static',False) if'args'in kw: args=Utils.to_list(kw['args']) if'--static'in args or'--static-libs'in args: @@ -184,7 +200,7 @@ def exec_cfg(self,kw): if not'okmsg'in kw: kw['okmsg']='yes' define_it() - self.parse_flags(ret,kw.get('uselib_store',kw['package'].upper()),kw.get('env',self.env),force_static=static) + self.parse_flags(ret,kw.get('uselib_store',kw['package'].upper()),kw.get('env',self.env),force_static=static,posix=kw.get('posix',None)) return ret @conf def check_cfg(self,*k,**kw): @@ -194,24 +210,37 @@ def check_cfg(self,*k,**kw): kw['args']=' '.join(lst[1:]) self.validate_cfg(kw) if'msg'in kw: - self.start_msg(kw['msg']) + self.start_msg(kw['msg'],**kw) ret=None try: ret=self.exec_cfg(kw) except self.errors.WafError: if'errmsg'in kw: - self.end_msg(kw['errmsg'],'YELLOW') + self.end_msg(kw['errmsg'],'YELLOW',**kw) if Logs.verbose>1: raise else: self.fatal('The configuration failed') else: + if not ret: + ret=True kw['success']=ret if'okmsg'in kw: - self.end_msg(self.ret_msg(kw['okmsg'],kw)) + self.end_msg(self.ret_msg(kw['okmsg'],kw),**kw) return ret +def build_fun(bld): + if bld.kw['compile_filename']: + node=bld.srcnode.make_node(bld.kw['compile_filename']) + node.write(bld.kw['code']) + o=bld(features=bld.kw['features'],source=bld.kw['compile_filename'],target='testprog') + for k,v in bld.kw.items(): + setattr(o,k,v) + if not bld.kw.get('quiet',None): + bld.conf.to_log("==>\n%s\n<=="%bld.kw['code']) @conf def validate_c(self,kw): + if not'build_fun'in kw: + kw['build_fun']=build_fun if not'env'in kw: kw['env']=self.env.derive() env=kw['env'] @@ -306,7 +335,7 @@ def validate_c(self,kw): kw['msg']='Checking for code snippet' if not'errmsg'in kw: kw['errmsg']='no' - for(flagsname,flagstype)in[('cxxflags','compiler'),('cflags','compiler'),('linkflags','linker')]: + for(flagsname,flagstype)in(('cxxflags','compiler'),('cflags','compiler'),('linkflags','linker')): if flagsname in kw: if not'msg'in kw: kw['msg']='Checking for %s flags %s'%(flagstype,kw[flagsname]) @@ -368,12 +397,12 @@ def post_check(self,*k,**kw): @conf def check(self,*k,**kw): self.validate_c(kw) - self.start_msg(kw['msg']) + self.start_msg(kw['msg'],**kw) ret=None try: - ret=self.run_c_code(*k,**kw) + ret=self.run_build(*k,**kw) except self.errors.ConfigurationError: - self.end_msg(kw['errmsg'],'YELLOW') + self.end_msg(kw['errmsg'],'YELLOW',**kw) if Logs.verbose>1: raise else: @@ -382,10 +411,10 @@ def check(self,*k,**kw): kw['success']=ret ret=self.post_check(*k,**kw) if not ret: - self.end_msg(kw['errmsg'],'YELLOW') + self.end_msg(kw['errmsg'],'YELLOW',**kw) self.fatal('The configuration failed %r'%ret) else: - self.end_msg(self.ret_msg(kw['okmsg'],kw)) + self.end_msg(self.ret_msg(kw['okmsg'],kw),**kw) return ret class test_exec(Task.Task): color='PINK' @@ -408,64 +437,6 @@ class test_exec(Task.Task): @after_method('apply_link') def test_exec_fun(self): self.create_task('test_exec',self.link_task.outputs[0]) -CACHE_RESULTS=1 -COMPILE_ERRORS=2 -@conf -def run_c_code(self,*k,**kw): - lst=[str(v)for(p,v)in kw.items()if p!='env'] - h=Utils.h_list(lst) - dir=self.bldnode.abspath()+os.sep+(not Utils.is_win32 and'.'or'')+'conf_check_'+Utils.to_hex(h) - try: - os.makedirs(dir) - except OSError: - pass - try: - os.stat(dir) - except OSError: - self.fatal('cannot use the configuration test folder %r'%dir) - cachemode=getattr(Options.options,'confcache',None) - if cachemode==CACHE_RESULTS: - try: - proj=ConfigSet.ConfigSet(os.path.join(dir,'cache_run_c_code')) - except OSError: - pass - else: - ret=proj['cache_run_c_code'] - if isinstance(ret,str)and ret.startswith('Test does not build'): - self.fatal(ret) - return ret - bdir=os.path.join(dir,'testbuild') - if not os.path.exists(bdir): - os.makedirs(bdir) - self.test_bld=bld=Build.BuildContext(top_dir=dir,out_dir=bdir) - bld.init_dirs() - bld.progress_bar=0 - bld.targets='*' - if kw['compile_filename']: - node=bld.srcnode.make_node(kw['compile_filename']) - node.write(kw['code']) - bld.logger=self.logger - bld.all_envs.update(self.all_envs) - bld.env=kw['env'] - o=bld(features=kw['features'],source=kw['compile_filename'],target='testprog') - for k,v in kw.items(): - setattr(o,k,v) - self.to_log("==>\n%s\n<=="%kw['code']) - bld.targets='*' - ret=-1 - try: - try: - bld.compile() - except Errors.WafError: - ret='Test does not build: %s'%Utils.ex_stack() - self.fatal(ret) - else: - ret=getattr(bld,'retval',0) - finally: - proj=ConfigSet.ConfigSet() - proj['cache_run_c_code']=ret - proj.store(os.path.join(dir,'cache_run_c_code')) - return ret @conf def check_cxx(self,*k,**kw): kw['compiler']='cxx' @@ -529,9 +500,7 @@ def get_define(self,key): def have_define(self,key): return(self.env.HAVE_PAT or'HAVE_%s')%Utils.quote_define_name(key) @conf -def write_config_header(self,configfile='',guard='',top=False,env=None,defines=True,headers=False,remove=True,define_prefix=''): - if env: - Logs.warn('Cannot pass env to write_config_header') +def write_config_header(self,configfile='',guard='',top=False,defines=True,headers=False,remove=True,define_prefix=''): if not configfile:configfile=WAF_CONFIG_H waf_guard=guard or'W_%s_WAF'%Utils.quote_define_name(configfile) node=top and self.bldnode or self.path.get_bld() @@ -554,12 +523,16 @@ def get_config_header(self,defines=True,headers=False,define_prefix=''): for x in self.env[INCKEYS]: lst.append('#include <%s>'%x) if defines: - for x in self.env[DEFKEYS]: - if self.is_defined(x): - val=self.get_define(x) - lst.append('#define %s %s'%(define_prefix+x,val)) - else: - lst.append('/* #undef %s */'%(define_prefix+x)) + tbl={} + for k in self.env['DEFINES']: + a,_,b=k.partition('=') + tbl[a]=b + for k in self.env[DEFKEYS]: + try: + txt='#define %s%s %s'%(define_prefix,k,tbl[k]) + except KeyError: + txt='/* #undef %s%s */'%(define_prefix,k) + lst.append(txt) return"\n".join(lst) @conf def cc_add_flags(conf): @@ -584,7 +557,7 @@ def cxx_load_tools(conf): conf.env.DEST_OS=Utils.unversioned_sys_platform() conf.load('cxx') @conf -def get_cc_version(conf,cc,gcc=False,icc=False): +def get_cc_version(conf,cc,gcc=False,icc=False,clang=False): cmd=cc+['-dM','-E','-'] env=conf.env.env or None try: @@ -602,8 +575,12 @@ def get_cc_version(conf,cc,gcc=False,icc=False): conf.fatal('Could not determine the compiler type') if icc and out.find('__INTEL_COMPILER')<0: conf.fatal('Not icc/icpc') + if clang and out.find('__clang__')<0: + conf.fatal('Not clang/clang++') + if not clang and out.find('__clang__')>=0: + conf.fatal('Could not find g++, if renamed try eg: CXX=g++48 waf configure') k={} - if icc or gcc: + if icc or gcc or clang: out=out.splitlines() for line in out: lst=shlex.split(line) @@ -645,9 +622,15 @@ def get_cc_version(conf,cc,gcc=False,icc=False): conf.env['CC_VERSION']=(ver[:-2],ver[-2],ver[-1]) else: if isD('__clang__'): - conf.env['CC_VERSION']=(k['__clang_major__'],k['__clang_minor__'],k['__clang_patchlevel__']) + try: + conf.env['CC_VERSION']=(k['__clang_major__'],k['__clang_minor__'],k['__clang_patchlevel__']) + except KeyError: + conf.env['CC_VERSION']=(k['__GNUC__'],k['__GNUC_MINOR__'],k['__GNUC_PATCHLEVEL__']) else: - conf.env['CC_VERSION']=(k['__GNUC__'],k['__GNUC_MINOR__'],k['__GNUC_PATCHLEVEL__']) + try: + conf.env['CC_VERSION']=(k['__GNUC__'],k['__GNUC_MINOR__'],k['__GNUC_PATCHLEVEL__']) + except KeyError: + conf.env['CC_VERSION']=(k['__GNUC__'],k['__GNUC_MINOR__'],0) return k @conf def get_xlc_version(conf,cc): @@ -687,7 +670,7 @@ def get_suncc_version(conf,cc): @conf def add_as_needed(self): if self.env.DEST_BINFMT=='elf'and'gcc'in(self.env.CXX_NAME,self.env.CC_NAME): - self.env.append_unique('LINKFLAGS','--as-needed') + self.env.append_unique('LINKFLAGS','-Wl,--as-needed') class cfgtask(Task.TaskBase): def display(self): return'' @@ -708,12 +691,10 @@ class cfgtask(Task.TaskBase): return 1 @conf def multicheck(self,*k,**kw): - self.start_msg(kw.get('msg','Executing %d configuration tests'%len(k))) + self.start_msg(kw.get('msg','Executing %d configuration tests'%len(k)),**kw) class par(object): def __init__(self): self.keep=False - self.cache_global=Options.cache_global - self.nocache=Options.options.nocache self.returned_tasks=[] self.task_sigs={} def total(self): @@ -741,6 +722,6 @@ def multicheck(self,*k,**kw): x.logger.memhandler.flush() for x in tasks: if x.hasrun!=Task.SUCCESS: - self.end_msg(kw.get('errmsg','no'),color='YELLOW') + self.end_msg(kw.get('errmsg','no'),color='YELLOW',**kw) self.fatal(kw.get('fatalmsg',None)or'One of the tests has failed, see the config.log for more information') - self.end_msg('ok') + self.end_msg('ok',**kw) diff --git a/waflib/Tools/c_preproc.py b/waflib/Tools/c_preproc.py index 1f99cd39..79f8c9cf 100644 --- a/waflib/Tools/c_preproc.py +++ b/waflib/Tools/c_preproc.py @@ -15,7 +15,7 @@ if Utils.is_win32: standard_includes=[] use_trigraphs=0 strict_quotes=0 -g_optrans={'not':'!','and':'&&','bitand':'&','and_eq':'&=','or':'||','bitor':'|','or_eq':'|=','xor':'^','xor_eq':'^=','compl':'~',} +g_optrans={'not':'!','not_eq':'!','and':'&&','and_eq':'&=','or':'||','or_eq':'|=','xor':'^','xor_eq':'^=','bitand':'&','bitor':'|','compl':'~',} re_lines=re.compile('^[ \t]*(#|%:)[ \t]*(ifdef|ifndef|if|else|elif|endif|include|import|define|undef|pragma)[ \t]*(.*)\r*$',re.IGNORECASE|re.MULTILINE) re_mac=re.compile("^[a-zA-Z_]\w*") re_fun=re.compile('^[a-zA-Z_][a-zA-Z0-9_]*[(]') @@ -71,17 +71,17 @@ def reduce_nums(val_1,val_2,val_op): elif d=='*':c=a*b elif d=='/':c=a/b elif d=='^':c=a^b - elif d=='|':c=a|b - elif d=='||':c=int(a or b) - elif d=='&':c=a&b - elif d=='&&':c=int(a and b) elif d=='==':c=int(a==b) - elif d=='!=':c=int(a!=b) + elif d=='|'or d=='bitor':c=a|b + elif d=='||'or d=='or':c=int(a or b) + elif d=='&'or d=='bitand':c=a&b + elif d=='&&'or d=='and':c=int(a and b) + elif d=='!='or d=='not_eq':c=int(a!=b) + elif d=='^'or d=='xor':c=int(a^b) elif d=='<=':c=int(a<=b) elif d=='<':c=int(a':c=int(a>b) elif d=='>=':c=int(a>=b) - elif d=='^':c=int(a^b) elif d=='<<':c=a<>':c=a>>b else:c=0 @@ -381,7 +381,8 @@ def extract_include(txt,defs): return'"',toks[0][1] else: if toks[0][1]=='<'and toks[-1][1]=='>': - return stringize(toks).lstrip('<').rstrip('>') + ret='<',stringize(toks).lstrip('<').rstrip('>') + return ret raise PreprocError("could not parse include %s."%txt) def parse_char(txt): if not txt:raise PreprocError("attempted to parse a null char") @@ -410,7 +411,9 @@ def tokenize_private(s): v=m(name) if v: if name==IDENT: - try:v=g_optrans[v];name=OP + try: + g_optrans[v]; + name=OP except KeyError: if v.lower()=="true": v=1 @@ -472,6 +475,9 @@ class c_parser(object): nd[tup]=ret return ret def tryfind(self,filename): + if filename.endswith('.moc'): + self.names.append(filename) + return None self.curfile=filename found=self.cached_find_resource(self.currentnode_stack[-1],filename) for n in self.nodepaths: @@ -480,8 +486,7 @@ class c_parser(object): found=self.cached_find_resource(n,filename) if found and not found in self.ban_includes: self.nodes.append(found) - if filename[-4:]!='.moc': - self.addlines(found) + self.addlines(found) else: if not filename in self.names: self.names.append(filename) @@ -519,8 +524,7 @@ class c_parser(object): try: self.parse_cache=bld.parse_cache except AttributeError: - bld.parse_cache={} - self.parse_cache=bld.parse_cache + self.parse_cache=bld.parse_cache={} self.current_file=node self.addlines(node) if env['DEFINES']: diff --git a/waflib/Tools/ccroot.py b/waflib/Tools/ccroot.py index 6a94573a..b90b6e19 100644 --- a/waflib/Tools/ccroot.py +++ b/waflib/Tools/ccroot.py @@ -75,12 +75,15 @@ class link_task(Task.Task): if self.env.DEST_BINFMT=='pe': name=name+'-'+nums[0] elif self.env.DEST_OS=='openbsd': - pattern='%s.%s.%s'%(pattern,nums[0],nums[1]) + pattern='%s.%s'%(pattern,nums[0]) + if len(nums)>=2: + pattern+='.%s'%nums[1] tmp=folder+os.sep+pattern%name target=self.generator.path.find_or_declare(tmp) self.set_outputs(target) class stlink_task(link_task): run_str='${AR} ${ARFLAGS} ${AR_TGT_F}${TGT} ${AR_SRC_F}${SRC}' + chmod=Utils.O644 def rm_tgt(cls): old=cls.run def wrap(self): @@ -111,7 +114,7 @@ def apply_link(self): except AttributeError: inst_to=self.link_task.__class__.inst_to if inst_to: - self.install_task=self.bld.install_files(inst_to,self.link_task.outputs[:],env=self.env,chmod=self.link_task.chmod) + self.install_task=self.bld.install_files(inst_to,self.link_task.outputs[:],env=self.env,chmod=self.link_task.chmod,task=self.link_task) @taskgen_method def use_rec(self,name,**kw): if name in self.tmp_use_not or name in self.tmp_use_seen: @@ -139,6 +142,8 @@ def use_rec(self,name,**kw): y.tmp_use_var='STLIB' p=self.tmp_use_prec for x in self.to_list(getattr(y,'use',[])): + if self.env["STLIB_"+x]: + continue try: p[x].append(name) except KeyError: @@ -190,11 +195,11 @@ def process_use(self): y=self.bld.get_tgen_by_name(x) var=y.tmp_use_var if var and link_task: - if var=='LIB'or y.tmp_use_stlib: + if var=='LIB'or y.tmp_use_stlib or x in names: self.env.append_value(var,[y.target[y.target.rfind(os.sep)+1:]]) self.link_task.dep_nodes.extend(y.link_task.outputs) tmp_path=y.link_task.outputs[0].parent.path_from(self.bld.bldnode) - self.env.append_value(var+'PATH',[tmp_path]) + self.env.append_unique(var+'PATH',[tmp_path]) else: if y.tmp_use_objects: self.add_objects_from_tgen(y) @@ -205,11 +210,11 @@ def process_use(self): for x in names: try: y=self.bld.get_tgen_by_name(x) - except Exception: + except Errors.WafError: if not self.env['STLIB_'+x]and not x in self.uselib: self.uselib.append(x) else: - for k in self.to_list(getattr(y,'uselib',[])): + for k in self.to_list(getattr(y,'use',[])): if not self.env['STLIB_'+k]and not k in self.uselib: self.uselib.append(k) @taskgen_method @@ -238,16 +243,17 @@ def get_uselib_vars(self): def propagate_uselib_vars(self): _vars=self.get_uselib_vars() env=self.env - for x in _vars: - y=x.lower() - env.append_unique(x,self.to_list(getattr(self,y,[]))) - for x in self.features: - for var in _vars: - compvar='%s_%s'%(var,x) - env.append_value(var,env[compvar]) - for x in self.to_list(getattr(self,'uselib',[])): - for v in _vars: - env.append_value(v,env[v+'_'+x]) + app=env.append_value + feature_uselib=self.features+self.to_list(getattr(self,'uselib',[])) + for var in _vars: + y=var.lower() + val=getattr(self,y,[]) + if val: + app(var,self.to_list(val)) + for x in feature_uselib: + val=env['%s_%s'%(var,x)] + if val: + app(var,val) @feature('cshlib','cxxshlib','fcshlib') @after_method('apply_link') def apply_implib(self): @@ -271,14 +277,19 @@ def apply_implib(self): self.link_task.dep_nodes.append(node) else: self.link_task.inputs.append(node) - try: - inst_to=self.install_path - except AttributeError: - inst_to=self.link_task.__class__.inst_to - if not inst_to: - return - self.implib_install_task=self.bld.install_as('${LIBDIR}/%s'%implib.name,implib,self.env) -re_vnum=re.compile('^([1-9]\\d*|0)[.]([1-9]\\d*|0)[.]([1-9]\\d*|0)$') + if getattr(self,'install_task',None): + try: + inst_to=self.install_path_implib + except AttributeError: + try: + inst_to=self.install_path + except AttributeError: + inst_to='${IMPLIBDIR}' + self.install_task.dest='${BINDIR}' + if not self.env.IMPLIBDIR: + self.env.IMPLIBDIR=self.env.LIBDIR + self.implib_install_task=self.bld.install_files(inst_to,implib,env=self.env,chmod=self.link_task.chmod,task=self.link_task) +re_vnum=re.compile('^([1-9]\\d*|0)([.]([1-9]\\d*|0)[.]([1-9]\\d*|0))?$') @feature('cshlib','cxxshlib','dshlib','fcshlib','vnum') @after_method('apply_link','propagate_uselib_vars') def apply_vnum(self): @@ -300,7 +311,10 @@ def apply_vnum(self): v=self.env.SONAME_ST%name2 self.env.append_value('LINKFLAGS',v.split()) if self.env.DEST_OS!='openbsd': - self.create_task('vnum',node,[node.parent.find_or_declare(name2),node.parent.find_or_declare(name3)]) + outs=[node.parent.find_or_declare(name3)] + if name2!=name3: + outs.append(node.parent.find_or_declare(name2)) + self.create_task('vnum',node,outs) if getattr(self,'install_task',None): self.install_task.hasrun=Task.SKIP_ME bld=self.bld @@ -311,9 +325,12 @@ def apply_vnum(self): self.vnum_install_task=(t1,) else: t1=bld.install_as(path+os.sep+name3,node,env=self.env,chmod=self.link_task.chmod) - t2=bld.symlink_as(path+os.sep+name2,name3) t3=bld.symlink_as(path+os.sep+libname,name3) - self.vnum_install_task=(t1,t2,t3) + if name2!=name3: + t2=bld.symlink_as(path+os.sep+name2,name3) + self.vnum_install_task=(t1,t2,t3) + else: + self.vnum_install_task=(t1,t3) if'-dynamiclib'in self.env['LINKFLAGS']: try: inst_to=self.install_path @@ -327,6 +344,8 @@ class vnum(Task.Task): color='CYAN' quient=True ext_in=['.bin'] + def keyword(self): + return'Symlinking' def run(self): for x in self.outputs: path=x.abspath() diff --git a/waflib/Tools/clang.py b/waflib/Tools/clang.py new file mode 100644 index 00000000..16932564 --- /dev/null +++ b/waflib/Tools/clang.py @@ -0,0 +1,20 @@ +#! /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 os,sys +from waflib.Tools import ccroot,ar,gcc +from waflib.Configure import conf +@conf +def find_clang(conf): + cc=conf.find_program('clang',var='CC') + conf.get_cc_version(cc,clang=True) + conf.env.CC_NAME='clang' +def configure(conf): + conf.find_clang() + conf.find_ar() + conf.gcc_common_flags() + conf.gcc_modifier_platform() + conf.cc_load_tools() + conf.cc_add_flags() + conf.link_add_flags() diff --git a/waflib/Tools/clangxx.py b/waflib/Tools/clangxx.py new file mode 100644 index 00000000..7407af96 --- /dev/null +++ b/waflib/Tools/clangxx.py @@ -0,0 +1,20 @@ +#! /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 os,sys +from waflib.Tools import ccroot,ar,gxx +from waflib.Configure import conf +@conf +def find_clangxx(conf): + cxx=conf.find_program('clang++',var='CXX') + conf.get_cc_version(cxx,clang=True) + conf.env.CXX_NAME='clang' +def configure(conf): + conf.find_clangxx() + conf.find_ar() + conf.gxx_common_flags() + conf.gxx_modifier_platform() + conf.cxx_load_tools() + conf.cxx_add_flags() + conf.link_add_flags() diff --git a/waflib/Tools/compiler_c.py b/waflib/Tools/compiler_c.py index 04504fa0..eed826be 100644 --- a/waflib/Tools/compiler_c.py +++ b/waflib/Tools/compiler_c.py @@ -2,17 +2,21 @@ # encoding: utf-8 # WARNING! Do not edit! http://waf.googlecode.com/git/docs/wafbook/single.html#_obtaining_the_waf_file -import os,sys,imp,types +import os,sys,imp,types,re from waflib.Tools import ccroot from waflib import Utils,Configure from waflib.Logs import debug -c_compiler={'win32':['msvc','gcc'],'cygwin':['gcc'],'darwin':['gcc'],'aix':['xlc','gcc'],'linux':['gcc','icc'],'sunos':['suncc','gcc'],'irix':['gcc','irixcc'],'hpux':['gcc'],'gnu':['gcc'],'java':['gcc','msvc','icc'],'default':['gcc'],} +c_compiler={'win32':['msvc','gcc','clang'],'cygwin':['gcc'],'darwin':['clang','gcc'],'aix':['xlc','gcc','clang'],'linux':['gcc','clang','icc'],'sunos':['suncc','gcc'],'irix':['gcc','irixcc'],'hpux':['gcc'],'gnu':['gcc','clang'],'java':['gcc','msvc','clang','icc'],'default':['gcc','clang'],} +def default_compilers(): + build_platform=Utils.unversioned_sys_platform() + possible_compiler_list=c_compiler.get(build_platform,c_compiler['default']) + return' '.join(possible_compiler_list) def configure(conf): - try:test_for_compiler=conf.options.check_c_compiler + try:test_for_compiler=conf.options.check_c_compiler or default_compilers() except AttributeError:conf.fatal("Add options(opt): opt.load('compiler_c')") - for compiler in test_for_compiler.split(): + for compiler in re.split('[ ,]+',test_for_compiler): conf.env.stash() - conf.start_msg('Checking for %r (c compiler)'%compiler) + conf.start_msg('Checking for %r (C compiler)'%compiler) try: conf.load(compiler) except conf.errors.ConfigurationError ,e: @@ -26,14 +30,11 @@ def configure(conf): break conf.end_msg(False) else: - conf.fatal('could not configure a c compiler!') + conf.fatal('could not configure a C compiler!') def options(opt): + test_for_compiler=default_compilers() opt.load_special_tools('c_*.py',ban=['c_dumbpreproc.py']) - global c_compiler - build_platform=Utils.unversioned_sys_platform() - possible_compiler_list=c_compiler[build_platform in c_compiler and build_platform or'default'] - test_for_compiler=' '.join(possible_compiler_list) - cc_compiler_opts=opt.add_option_group("C Compiler Options") - cc_compiler_opts.add_option('--check-c-compiler',default="%s"%test_for_compiler,help='On this platform (%s) the following C-Compiler will be checked by default: "%s"'%(build_platform,test_for_compiler),dest="check_c_compiler") + cc_compiler_opts=opt.add_option_group('Configuration options') + cc_compiler_opts.add_option('--check-c-compiler',default=None,help='list of C compilers to try [%s]'%test_for_compiler,dest="check_c_compiler") for x in test_for_compiler.split(): opt.load('%s'%x) diff --git a/waflib/Tools/compiler_cxx.py b/waflib/Tools/compiler_cxx.py index 14b7c7da..1990fb58 100644 --- a/waflib/Tools/compiler_cxx.py +++ b/waflib/Tools/compiler_cxx.py @@ -2,17 +2,21 @@ # encoding: utf-8 # WARNING! Do not edit! http://waf.googlecode.com/git/docs/wafbook/single.html#_obtaining_the_waf_file -import os,sys,imp,types +import os,sys,imp,types,re from waflib.Tools import ccroot from waflib import Utils,Configure from waflib.Logs import debug -cxx_compiler={'win32':['msvc','g++'],'cygwin':['g++'],'darwin':['g++'],'aix':['xlc++','g++'],'linux':['g++','icpc'],'sunos':['sunc++','g++'],'irix':['g++'],'hpux':['g++'],'gnu':['g++'],'java':['g++','msvc','icpc'],'default':['g++']} +cxx_compiler={'win32':['msvc','g++','clang++'],'cygwin':['g++'],'darwin':['clang++','g++'],'aix':['xlc++','g++','clang++'],'linux':['g++','clang++','icpc'],'sunos':['sunc++','g++'],'irix':['g++'],'hpux':['g++'],'gnu':['g++','clang++'],'java':['g++','msvc','clang++','icpc'],'default':['g++','clang++']} +def default_compilers(): + build_platform=Utils.unversioned_sys_platform() + possible_compiler_list=cxx_compiler.get(build_platform,cxx_compiler['default']) + return' '.join(possible_compiler_list) def configure(conf): - try:test_for_compiler=conf.options.check_cxx_compiler + try:test_for_compiler=conf.options.check_cxx_compiler or default_compilers() except AttributeError:conf.fatal("Add options(opt): opt.load('compiler_cxx')") - for compiler in test_for_compiler.split(): + for compiler in re.split('[ ,]+',test_for_compiler): conf.env.stash() - conf.start_msg('Checking for %r (c++ compiler)'%compiler) + conf.start_msg('Checking for %r (C++ compiler)'%compiler) try: conf.load(compiler) except conf.errors.ConfigurationError ,e: @@ -26,14 +30,11 @@ def configure(conf): break conf.end_msg(False) else: - conf.fatal('could not configure a c++ compiler!') + conf.fatal('could not configure a C++ compiler!') def options(opt): + test_for_compiler=default_compilers() opt.load_special_tools('cxx_*.py') - global cxx_compiler - build_platform=Utils.unversioned_sys_platform() - possible_compiler_list=cxx_compiler[build_platform in cxx_compiler and build_platform or'default'] - test_for_compiler=' '.join(possible_compiler_list) - cxx_compiler_opts=opt.add_option_group('C++ Compiler Options') - cxx_compiler_opts.add_option('--check-cxx-compiler',default="%s"%test_for_compiler,help='On this platform (%s) the following C++ Compiler will be checked by default: "%s"'%(build_platform,test_for_compiler),dest="check_cxx_compiler") + cxx_compiler_opts=opt.add_option_group('Configuration options') + cxx_compiler_opts.add_option('--check-cxx-compiler',default=None,help='list of C++ compilers to try [%s]'%test_for_compiler,dest="check_cxx_compiler") for x in test_for_compiler.split(): opt.load('%s'%x) diff --git a/waflib/Tools/compiler_d.py b/waflib/Tools/compiler_d.py index ee173e10..3bc19991 100644 --- a/waflib/Tools/compiler_d.py +++ b/waflib/Tools/compiler_d.py @@ -2,12 +2,19 @@ # encoding: utf-8 # WARNING! Do not edit! http://waf.googlecode.com/git/docs/wafbook/single.html#_obtaining_the_waf_file -import os,sys,imp,types +import os,sys,imp,types,re from waflib import Utils,Configure,Options,Logs +d_compiler={'default':['gdc','dmd','ldc2']} +def default_compilers(): + build_platform=Utils.unversioned_sys_platform() + possible_compiler_list=d_compiler.get(build_platform,d_compiler['default']) + return' '.join(possible_compiler_list) def configure(conf): - for compiler in conf.options.dcheck.split(','): + try:test_for_compiler=conf.options.check_d_compiler or default_compilers() + except AttributeError:conf.fatal("Add options(opt): opt.load('compiler_d')") + for compiler in re.split('[ ,]+',test_for_compiler): conf.env.stash() - conf.start_msg('Checking for %r (d compiler)'%compiler) + conf.start_msg('Checking for %r (D compiler)'%compiler) try: conf.load(compiler) except conf.errors.ConfigurationError ,e: @@ -21,9 +28,10 @@ def configure(conf): break conf.end_msg(False) else: - conf.fatal('no suitable d compiler was found') + conf.fatal('could not configure a D compiler!') def options(opt): - d_compiler_opts=opt.add_option_group('D Compiler Options') - d_compiler_opts.add_option('--check-d-compiler',default='gdc,dmd,ldc2',action='store',help='check for the compiler [Default:gdc,dmd,ldc2]',dest='dcheck') - for d_compiler in['gdc','dmd','ldc2']: - opt.load('%s'%d_compiler) + test_for_compiler=default_compilers() + d_compiler_opts=opt.add_option_group('Configuration options') + d_compiler_opts.add_option('--check-d-compiler',default=None,help='list of D compilers to try [%s]'%test_for_compiler,dest='check_d_compiler') + for x in test_for_compiler.split(): + opt.load('%s'%x) diff --git a/waflib/Tools/compiler_fc.py b/waflib/Tools/compiler_fc.py index ec5d2ead..77f84816 100644 --- a/waflib/Tools/compiler_fc.py +++ b/waflib/Tools/compiler_fc.py @@ -2,21 +2,20 @@ # encoding: utf-8 # WARNING! Do not edit! http://waf.googlecode.com/git/docs/wafbook/single.html#_obtaining_the_waf_file -import os,sys,imp,types +import os,sys,imp,types,re from waflib import Utils,Configure,Options,Logs,Errors from waflib.Tools import fc fc_compiler={'win32':['gfortran','ifort'],'darwin':['gfortran','g95','ifort'],'linux':['gfortran','g95','ifort'],'java':['gfortran','g95','ifort'],'default':['gfortran'],'aix':['gfortran']} -def __list_possible_compiler(platform): - try: - return fc_compiler[platform] - except KeyError: - return fc_compiler["default"] +def default_compilers(): + build_platform=Utils.unversioned_sys_platform() + possible_compiler_list=fc_compiler.get(build_platform,fc_compiler['default']) + return' '.join(possible_compiler_list) def configure(conf): - try:test_for_compiler=conf.options.check_fc + try:test_for_compiler=conf.options.check_fortran_compiler or default_compilers() except AttributeError:conf.fatal("Add options(opt): opt.load('compiler_fc')") - for compiler in test_for_compiler.split(): + for compiler in re.split('[ ,]+',test_for_compiler): conf.env.stash() - conf.start_msg('Checking for %r (fortran compiler)'%compiler) + conf.start_msg('Checking for %r (Fortran compiler)'%compiler) try: conf.load(compiler) except conf.errors.ConfigurationError ,e: @@ -30,14 +29,11 @@ def configure(conf): break conf.end_msg(False) else: - conf.fatal('could not configure a fortran compiler!') + conf.fatal('could not configure a Fortran compiler!') def options(opt): + test_for_compiler=default_compilers() opt.load_special_tools('fc_*.py') - build_platform=Utils.unversioned_sys_platform() - detected_platform=Options.platform - possible_compiler_list=__list_possible_compiler(detected_platform) - test_for_compiler=' '.join(possible_compiler_list) - fortran_compiler_opts=opt.add_option_group("Fortran Compiler Options") - fortran_compiler_opts.add_option('--check-fortran-compiler',default="%s"%test_for_compiler,help='On this platform (%s) the following Fortran Compiler will be checked by default: "%s"'%(detected_platform,test_for_compiler),dest="check_fc") - for compiler in test_for_compiler.split(): - opt.load('%s'%compiler) + fortran_compiler_opts=opt.add_option_group('Configuration options') + fortran_compiler_opts.add_option('--check-fortran-compiler',default=None,help='list of Fortran compiler to try [%s]'%test_for_compiler,dest="check_fortran_compiler") + for x in test_for_compiler.split(): + opt.load('%s'%x) diff --git a/waflib/Tools/cxx.py b/waflib/Tools/cxx.py index b744a8d2..87027390 100644 --- a/waflib/Tools/cxx.py +++ b/waflib/Tools/cxx.py @@ -11,7 +11,7 @@ def cxx_hook(self,node): if not'.c'in TaskGen.task_gen.mappings: TaskGen.task_gen.mappings['.c']=TaskGen.task_gen.mappings['.cpp'] class cxx(Task.Task): - run_str='${CXX} ${ARCH_ST:ARCH} ${CXXFLAGS} ${CPPFLAGS} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ${CPPPATH_ST:INCPATHS} ${DEFINES_ST:DEFINES} ${CXX_SRC_F}${SRC} ${CXX_TGT_F}${TGT}' + run_str='${CXX} ${ARCH_ST:ARCH} ${CXXFLAGS} ${CPPFLAGS} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ${CPPPATH_ST:INCPATHS} ${DEFINES_ST:DEFINES} ${CXX_SRC_F}${SRC} ${CXX_TGT_F}${TGT[0].abspath()}' vars=['CXXDEPS'] ext_in=['.h'] scan=c_preproc.scan diff --git a/waflib/Tools/dmd.py b/waflib/Tools/dmd.py index b6e3303d..fb0999e1 100644 --- a/waflib/Tools/dmd.py +++ b/waflib/Tools/dmd.py @@ -8,9 +8,9 @@ from waflib.Configure import conf @conf def find_dmd(conf): conf.find_program(['dmd','dmd2','ldc'],var='D') - out=conf.cmd_and_log([conf.env.D,'--help']) + out=conf.cmd_and_log(conf.env.D+['--help']) if out.find("D Compiler v")==-1: - out=conf.cmd_and_log([conf.env.D,'-version']) + out=conf.cmd_and_log(conf.env.D+['-version']) if out.find("based on DMD v1.")==-1: conf.fatal("detected compiler is not dmd/ldc") @conf @@ -40,7 +40,7 @@ def common_flags_dmd(conf): def configure(conf): conf.find_dmd() if sys.platform=='win32': - out=conf.cmd_and_log([conf.env.D,'--help']) + out=conf.cmd_and_log(conf.env.D+['--help']) if out.find("D Compiler v2.")>-1: conf.fatal('dmd2 on Windows is not supported, use gdc or ldc2 instead') conf.load('ar') diff --git a/waflib/Tools/fc.py b/waflib/Tools/fc.py index 35897998..12785abc 100644 --- a/waflib/Tools/fc.py +++ b/waflib/Tools/fc.py @@ -89,8 +89,6 @@ class fcprogram(ccroot.link_task): class fcshlib(fcprogram): inst_to='${LIBDIR}' class fcprogram_test(fcprogram): - def can_retrieve_cache(self): - return False def runnable_status(self): ret=super(fcprogram_test,self).runnable_status() if ret==Task.SKIP_ME: diff --git a/waflib/Tools/fc_config.py b/waflib/Tools/fc_config.py index 580eac73..4b228799 100644 --- a/waflib/Tools/fc_config.py +++ b/waflib/Tools/fc_config.py @@ -2,10 +2,10 @@ # 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 +import re,os,sys,shlex from waflib.Configure import conf -from waflib.TaskGen import feature,after_method,before_method -from waflib import Build,Utils +from waflib.TaskGen import feature,before_method +from waflib import Utils FC_FRAGMENT=' program main\n end program main\n' FC_FRAGMENT2=' PROGRAM MAIN\n END\n' @conf @@ -115,7 +115,7 @@ def is_link_verbose(self,txt): @conf def check_fortran_verbose_flag(self,*k,**kw): self.start_msg('fortran link verbose flag') - for x in['-v','--verbose','-verbose','-V']: + 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: @@ -148,32 +148,32 @@ def parse_fortran_link(lines): return final_flags SPACE_OPTS=re.compile('^-[LRuYz]$') NOSPACE_OPTS=re.compile('^-[RL]') +def _parse_flink_token(lexer,token,tmp_flags): + 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 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) + t=_parse_flink_token(lexer,t,tmp_flags) final_flags.extend(tmp_flags) return final_flags @conf @@ -240,9 +240,9 @@ def link_main_routines_tg_method(self): 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"]: + 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'') @@ -274,7 +274,7 @@ def set_lib_pat(self): self.env['fcshlib_PATTERN']=self.env['pyext_PATTERN'] @conf def detect_openmp(self): - for x in['-fopenmp','-openmp','-mp','-xopenmp','-omp','-qsmp=omp']: + 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: diff --git a/waflib/Tools/flex.py b/waflib/Tools/flex.py index 13f6207e..838b2fc8 100644 --- a/waflib/Tools/flex.py +++ b/waflib/Tools/flex.py @@ -28,5 +28,5 @@ waflib.TaskGen.declare_chain(name='flex',rule=flexfun,ext_in='.l',decider=decide def configure(conf): conf.find_program('flex',var='FLEX') conf.env.FLEXFLAGS=['-t'] - if re.search(r"\\msys\\[0-9.]+\\bin\\flex.exe$",conf.env.FLEX): + if re.search(r"\\msys\\[0-9.]+\\bin\\flex.exe$",conf.env.FLEX[0]): conf.env.FLEX_MSYS=True diff --git a/waflib/Tools/g95.py b/waflib/Tools/g95.py index 9bc331aa..abc9ec12 100644 --- a/waflib/Tools/g95.py +++ b/waflib/Tools/g95.py @@ -9,7 +9,6 @@ from waflib.Configure import conf @conf def find_g95(conf): fc=conf.find_program('g95',var='FC') - fc=conf.cmd_to_list(fc) conf.get_g95_version(fc) conf.env.FC_NAME='G95' @conf diff --git a/waflib/Tools/gcc.py b/waflib/Tools/gcc.py index aca49ca2..dfdbca28 100644 --- a/waflib/Tools/gcc.py +++ b/waflib/Tools/gcc.py @@ -2,15 +2,15 @@ # encoding: utf-8 # WARNING! Do not edit! http://waf.googlecode.com/git/docs/wafbook/single.html#_obtaining_the_waf_file +import os,sys +from waflib import Configure,Options,Utils from waflib.Tools import ccroot,ar from waflib.Configure import conf @conf def find_gcc(conf): cc=conf.find_program(['gcc','cc'],var='CC') - cc=conf.cmd_to_list(cc) conf.get_cc_version(cc,gcc=True) conf.env.CC_NAME='gcc' - conf.env.CC=cc @conf def gcc_common_flags(conf): v=conf.env diff --git a/waflib/Tools/gdc.py b/waflib/Tools/gdc.py index da966ec0..8519ce49 100644 --- a/waflib/Tools/gdc.py +++ b/waflib/Tools/gdc.py @@ -8,8 +8,8 @@ from waflib.Configure import conf @conf def find_gdc(conf): conf.find_program('gdc',var='D') - out=conf.cmd_and_log([conf.env.D,'--version']) - if out.find("gdc ")==-1: + out=conf.cmd_and_log(conf.env.D+['--version']) + if out.find("gdc")==-1: conf.fatal("detected compiler is not gdc") @conf def common_flags_gdc(conf): diff --git a/waflib/Tools/gfortran.py b/waflib/Tools/gfortran.py index 854a93db..ce173b3e 100644 --- a/waflib/Tools/gfortran.py +++ b/waflib/Tools/gfortran.py @@ -9,7 +9,6 @@ from waflib.Configure import conf @conf def find_gfortran(conf): fc=conf.find_program(['gfortran','g77'],var='FC') - fc=conf.cmd_to_list(fc) conf.get_gfortran_version(fc) conf.env.FC_NAME='GFORTRAN' @conf diff --git a/waflib/Tools/glib2.py b/waflib/Tools/glib2.py index 1d75510b..eeca3356 100644 --- a/waflib/Tools/glib2.py +++ b/waflib/Tools/glib2.py @@ -3,8 +3,9 @@ # WARNING! Do not edit! http://waf.googlecode.com/git/docs/wafbook/single.html#_obtaining_the_waf_file import os -from waflib import Task,Utils,Options,Errors,Logs -from waflib.TaskGen import taskgen_method,before_method,after_method,feature +from waflib import Context,Task,Utils,Options,Errors,Logs +from waflib.TaskGen import taskgen_method,before_method,after_method,feature,extension +from waflib.Configure import conf @taskgen_method def add_marshal_file(self,filename,prefix): if not hasattr(self,'marshal_list'): @@ -98,14 +99,6 @@ def add_settings_enums(self,namespace,filename_list): if type(filename_list)!='list': filename_list=[filename_list] self.settings_enum_files=filename_list -def r_change_ext(self,ext): - name=self.name - k=name.rfind('.') - if k>=0: - name=name[:k]+ext - else: - name=name+ext - return self.parent.find_or_declare([name]) @feature('glib2') def process_settings(self): enums_tgt_node=[] @@ -136,7 +129,7 @@ def process_settings(self): source_list=enums_tgt_node+[schema_node] schema_task.set_inputs(source_list) schema_task.env['GLIB_COMPILE_SCHEMAS_OPTIONS']=[("--schema-file="+k.abspath())for k in source_list] - target_node=r_change_ext(schema_node,'.xml.valid') + target_node=schema_node.change_ext('.xml.valid') schema_task.set_outputs(target_node) schema_task.env['GLIB_VALIDATE_SCHEMA_OUTPUT']=target_node.abspath() def compile_schemas_callback(bld): @@ -155,10 +148,69 @@ def process_settings(self): class glib_validate_schema(Task.Task): run_str='rm -f ${GLIB_VALIDATE_SCHEMA_OUTPUT} && ${GLIB_COMPILE_SCHEMAS} --dry-run ${GLIB_COMPILE_SCHEMAS_OPTIONS} && touch ${GLIB_VALIDATE_SCHEMA_OUTPUT}' color='PINK' -def configure(conf): +@extension('.gresource.xml') +def process_gresource_source(self,node): + if not self.env['GLIB_COMPILE_RESOURCES']: + raise Errors.WafError("Unable to process GResource file - glib-compile-resources was not found during configure") + if'gresource'in self.features: + return + h_node=node.change_ext('_xml.h') + c_node=node.change_ext('_xml.c') + self.create_task('glib_gresource_source',node,[h_node,c_node]) + self.source.append(c_node) +@feature('gresource') +def process_gresource_bundle(self): + for i in self.to_list(self.source): + node=self.path.find_resource(i) + task=self.create_task('glib_gresource_bundle',node,node.change_ext('')) + inst_to=getattr(self,'install_path',None) + if inst_to: + self.bld.install_files(inst_to,task.outputs) +class glib_gresource_base(Task.Task): + color='BLUE' + base_cmd='${GLIB_COMPILE_RESOURCES} --sourcedir=${SRC[0].parent.srcpath()} --sourcedir=${SRC[0].bld_dir()}' + def scan(self): + bld=self.generator.bld + kw={} + try: + if not kw.get('cwd',None): + kw['cwd']=bld.cwd + except AttributeError: + bld.cwd=kw['cwd']=bld.variant_dir + kw['quiet']=Context.BOTH + cmd=Utils.subst_vars('${GLIB_COMPILE_RESOURCES} --sourcedir=%s --sourcedir=%s --generate-dependencies %s'%(self.inputs[0].parent.srcpath(),self.inputs[0].bld_dir(),self.inputs[0].bldpath()),self.env) + output=bld.cmd_and_log(cmd,**kw) + nodes=[] + names=[] + for dep in output.splitlines(): + if dep: + node=bld.bldnode.find_node(dep) + if node: + nodes.append(node) + else: + names.append(dep) + return(nodes,names) +class glib_gresource_source(glib_gresource_base): + vars=['GLIB_COMPILE_RESOURCES'] + fun_h=Task.compile_fun_shell(glib_gresource_base.base_cmd+' --target=${TGT[0].abspath()} --generate-header ${SRC}') + fun_c=Task.compile_fun_shell(glib_gresource_base.base_cmd+' --target=${TGT[1].abspath()} --generate-source ${SRC}') + ext_out=['.h'] + def run(self): + return self.fun_h[0](self)or self.fun_c[0](self) +class glib_gresource_bundle(glib_gresource_base): + run_str=glib_gresource_base.base_cmd+' --target=${TGT} ${SRC}' + shell=True +@conf +def find_glib_genmarshal(conf): conf.find_program('glib-genmarshal',var='GLIB_GENMARSHAL') - conf.find_perl_program('glib-mkenums',var='GLIB_MKENUMS') - conf.find_program('glib-compile-schemas',var='GLIB_COMPILE_SCHEMAS',mandatory=False) +@conf +def find_glib_mkenums(conf): + if not conf.env.PERL: + conf.find_program('perl',var='PERL') + conf.find_program('glib-mkenums',interpreter='PERL',var='GLIB_MKENUMS') +@conf +def find_glib_compile_schemas(conf): + conf.find_program('glib-compile-schemas',var='GLIB_COMPILE_SCHEMAS') def getstr(varname): return getattr(Options.options,varname,getattr(conf.env,varname,'')) gsettingsschemadir=getstr('GSETTINGSSCHEMADIR') @@ -169,5 +221,14 @@ def configure(conf): datadir=os.path.join(prefix,'share') gsettingsschemadir=os.path.join(datadir,'glib-2.0','schemas') conf.env['GSETTINGSSCHEMADIR']=gsettingsschemadir +@conf +def find_glib_compile_resources(conf): + conf.find_program('glib-compile-resources',var='GLIB_COMPILE_RESOURCES') +def configure(conf): + conf.find_glib_genmarshal() + conf.find_glib_mkenums() + conf.find_glib_compile_schemas(mandatory=False) + conf.find_glib_compile_resources(mandatory=False) def options(opt): - opt.add_option('--gsettingsschemadir',help='GSettings schema location [Default: ${datadir}/glib-2.0/schemas]',default='',dest='GSETTINGSSCHEMADIR') + gr=opt.add_option_group('Installation directories') + gr.add_option('--gsettingsschemadir',help='GSettings schema location [DATADIR/glib-2.0/schemas]',default='',dest='GSETTINGSSCHEMADIR') diff --git a/waflib/Tools/gnu_dirs.py b/waflib/Tools/gnu_dirs.py index 9c8a3041..08eafd42 100644 --- a/waflib/Tools/gnu_dirs.py +++ b/waflib/Tools/gnu_dirs.py @@ -2,29 +2,30 @@ # encoding: utf-8 # WARNING! Do not edit! http://waf.googlecode.com/git/docs/wafbook/single.html#_obtaining_the_waf_file -import os +import os,re from waflib import Utils,Options,Context -_options=[x.split(', ')for x in''' -bindir, user executables, ${EXEC_PREFIX}/bin -sbindir, system admin executables, ${EXEC_PREFIX}/sbin -libexecdir, program executables, ${EXEC_PREFIX}/libexec -sysconfdir, read-only single-machine data, ${PREFIX}/etc -sharedstatedir, modifiable architecture-independent data, ${PREFIX}/com -localstatedir, modifiable single-machine data, ${PREFIX}/var -libdir, object code libraries, ${EXEC_PREFIX}/lib -includedir, C header files, ${PREFIX}/include -oldincludedir, C header files for non-gcc, /usr/include -datarootdir, read-only arch.-independent data root, ${PREFIX}/share -datadir, read-only architecture-independent data, ${DATAROOTDIR} -infodir, info documentation, ${DATAROOTDIR}/info +gnuopts=''' +bindir, user commands, ${EXEC_PREFIX}/bin +sbindir, system binaries, ${EXEC_PREFIX}/sbin +libexecdir, program-specific binaries, ${EXEC_PREFIX}/libexec +sysconfdir, host-specific configuration, ${PREFIX}/etc +sharedstatedir, architecture-independent variable data, ${PREFIX}/com +localstatedir, variable data, ${PREFIX}/var +libdir, object code libraries, ${EXEC_PREFIX}/lib%s +includedir, header files, ${PREFIX}/include +oldincludedir, header files for non-GCC compilers, /usr/include +datarootdir, architecture-independent data root, ${PREFIX}/share +datadir, architecture-independent data, ${DATAROOTDIR} +infodir, GNU "info" documentation, ${DATAROOTDIR}/info localedir, locale-dependent data, ${DATAROOTDIR}/locale -mandir, man documentation, ${DATAROOTDIR}/man +mandir, manual pages, ${DATAROOTDIR}/man docdir, documentation root, ${DATAROOTDIR}/doc/${PACKAGE} -htmldir, html documentation, ${DOCDIR} -dvidir, dvi documentation, ${DOCDIR} -pdfdir, pdf documentation, ${DOCDIR} -psdir, ps documentation, ${DOCDIR} -'''.split('\n')if x] +htmldir, HTML documentation, ${DOCDIR} +dvidir, DVI documentation, ${DOCDIR} +pdfdir, PDF documentation, ${DOCDIR} +psdir, PostScript documentation, ${DOCDIR} +'''%Utils.lib64() +_options=[x.split(', ')for x in gnuopts.splitlines()if x] def configure(conf): def get_param(varname,default): return getattr(Options.options,varname,'')or default @@ -45,10 +46,10 @@ def configure(conf): except TypeError: complete=False if not complete: - lst=[name for name,_,_ in _options if not env[name.upper()]] + lst=[x for x,_,_ in _options if not env[x.upper()]] raise conf.errors.WafError('Variable substitution failure %r'%lst) def options(opt): - inst_dir=opt.add_option_group('Installation directories','By default, "waf install" will put the files in\ + inst_dir=opt.add_option_group('Installation prefix','By default, "waf install" will put the files in\ "/usr/local/bin", "/usr/local/lib" etc. An installation prefix other\ than "/usr/local" can be given using "--prefix", for example "--prefix=$HOME"') for k in('--prefix','--destdir'): @@ -56,10 +57,10 @@ def options(opt): if option: opt.parser.remove_option(k) inst_dir.add_option(option) - inst_dir.add_option('--exec-prefix',help='installation prefix [Default: ${PREFIX}]',default='',dest='EXEC_PREFIX') - dirs_options=opt.add_option_group('Pre-defined installation directories','') + inst_dir.add_option('--exec-prefix',help='installation prefix for binaries [PREFIX]',default='',dest='EXEC_PREFIX') + dirs_options=opt.add_option_group('Installation directories') for name,help,default in _options: option_name='--'+name str_default=default - str_help='%s [Default: %s]'%(help,str_default) + str_help='%s [%s]'%(help,re.sub(r'\$\{([^}]+)\}',r'\1',str_default)) dirs_options.add_option(option_name,help=str_help,default='',dest=name.upper()) diff --git a/waflib/Tools/gxx.py b/waflib/Tools/gxx.py index 475f7fd1..375c9d28 100644 --- a/waflib/Tools/gxx.py +++ b/waflib/Tools/gxx.py @@ -2,15 +2,15 @@ # encoding: utf-8 # WARNING! Do not edit! http://waf.googlecode.com/git/docs/wafbook/single.html#_obtaining_the_waf_file +import os,sys +from waflib import Configure,Options,Utils from waflib.Tools import ccroot,ar from waflib.Configure import conf @conf def find_gxx(conf): cxx=conf.find_program(['g++','c++'],var='CXX') - cxx=conf.cmd_to_list(cxx) conf.get_cc_version(cxx,gcc=True) conf.env.CXX_NAME='gcc' - conf.env.CXX=cxx @conf def gxx_common_flags(conf): v=conf.env diff --git a/waflib/Tools/icc.py b/waflib/Tools/icc.py index 7c75e18d..d08c7f4f 100644 --- a/waflib/Tools/icc.py +++ b/waflib/Tools/icc.py @@ -9,17 +9,9 @@ from waflib.Configure import conf def find_icc(conf): if sys.platform=='cygwin': conf.fatal('The Intel compiler does not work on Cygwin') - v=conf.env - cc=None - if v['CC']:cc=v['CC'] - elif'CC'in conf.environ:cc=conf.environ['CC'] - if not cc:cc=conf.find_program('icc',var='CC') - if not cc:cc=conf.find_program('ICL',var='CC') - if not cc:conf.fatal('Intel C Compiler (icc) was not found') - cc=conf.cmd_to_list(cc) + cc=conf.find_program(['icc','ICL'],var='CC') conf.get_cc_version(cc,icc=True) - v['CC']=cc - v['CC_NAME']='icc' + conf.env.CC_NAME='icc' def configure(conf): conf.find_icc() conf.find_ar() diff --git a/waflib/Tools/icpc.py b/waflib/Tools/icpc.py index 14a53251..e071e409 100644 --- a/waflib/Tools/icpc.py +++ b/waflib/Tools/icpc.py @@ -9,16 +9,9 @@ from waflib.Configure import conf def find_icpc(conf): if sys.platform=='cygwin': conf.fatal('The Intel compiler does not work on Cygwin') - v=conf.env - cxx=None - if v['CXX']:cxx=v['CXX'] - elif'CXX'in conf.environ:cxx=conf.environ['CXX'] - if not cxx:cxx=conf.find_program('icpc',var='CXX') - if not cxx:conf.fatal('Intel C++ Compiler (icpc) was not found') - cxx=conf.cmd_to_list(cxx) + cxx=conf.find_program('icpc',var='CXX') conf.get_cc_version(cxx,icc=True) - v['CXX']=cxx - v['CXX_NAME']='icc' + conf.env.CXX_NAME='icc' def configure(conf): conf.find_icpc() conf.find_ar() diff --git a/waflib/Tools/ifort.py b/waflib/Tools/ifort.py index a9f2528d..b0bbf28f 100644 --- a/waflib/Tools/ifort.py +++ b/waflib/Tools/ifort.py @@ -9,7 +9,6 @@ from waflib.Configure import conf @conf def find_ifort(conf): fc=conf.find_program('ifort',var='FC') - fc=conf.cmd_to_list(fc) conf.get_ifort_version(fc) conf.env.FC_NAME='IFORT' @conf @@ -29,8 +28,11 @@ def ifort_modifier_platform(conf): ifort_modifier_func() @conf def get_ifort_version(conf,fc): - version_re=re.compile(r"ifort\s*\(IFORT\)\s*(?P\d*)\.(?P\d*)",re.I).search - cmd=fc+['--version'] + version_re=re.compile(r"Intel[\sa-zA-Z()0-9,-]*Version\s*(?P\d*)\.(?P\d*)",re.I).search + if Utils.is_win32: + cmd=fc + else: + cmd=fc+['-logo'] out,err=fc_config.getoutput(conf,cmd,stdin=False) if out: match=version_re(out) diff --git a/waflib/Tools/intltool.py b/waflib/Tools/intltool.py index d558674f..b8a63182 100644 --- a/waflib/Tools/intltool.py +++ b/waflib/Tools/intltool.py @@ -3,40 +3,56 @@ # WARNING! Do not edit! http://waf.googlecode.com/git/docs/wafbook/single.html#_obtaining_the_waf_file import os,re -from waflib import Configure,TaskGen,Task,Utils,Runner,Options,Build,Logs +from waflib import Configure,Context,TaskGen,Task,Utils,Runner,Options,Build,Logs import waflib.Tools.ccroot -from waflib.TaskGen import feature,before_method +from waflib.TaskGen import feature,before_method,taskgen_method from waflib.Logs import error +from waflib.Configure import conf +_style_flags={'ba':'-b','desktop':'-d','keys':'-k','quoted':'--quoted-style','quotedxml':'--quotedxml-style','rfc822deb':'-r','schemas':'-s','xml':'-x',} +@taskgen_method +def ensure_localedir(self): + if not self.env.LOCALEDIR: + if self.env.DATAROOTDIR: + self.env.LOCALEDIR=os.path.join(self.env.DATAROOTDIR,'locale') + else: + self.env.LOCALEDIR=os.path.join(self.env.PREFIX,'share','locale') @before_method('process_source') @feature('intltool_in') def apply_intltool_in_f(self): try:self.meths.remove('process_source') except ValueError:pass - if not self.env.LOCALEDIR: - self.env.LOCALEDIR=self.env.PREFIX+'/share/locale' + self.ensure_localedir() + podir=getattr(self,'podir','.') + podirnode=self.path.find_dir(podir) + if not podirnode: + error("could not find the podir %r"%podir) + return + cache=getattr(self,'intlcache','.intlcache') + self.env.INTLCACHE=[os.path.join(str(self.path.get_bld()),podir,cache)] + self.env.INTLPODIR=podirnode.bldpath() + self.env.append_value('INTLFLAGS',getattr(self,'flags',self.env.INTLFLAGS_DEFAULT)) + if'-c'in self.env.INTLFLAGS: + self.bld.fatal('Redundant -c flag in intltool task %r'%self) + style=getattr(self,'style',None) + if style: + try: + style_flag=_style_flags[style] + except KeyError: + self.bld.fatal('intltool_in style "%s" is not valid'%style) + self.env.append_unique('INTLFLAGS',[style_flag]) for i in self.to_list(self.source): node=self.path.find_resource(i) - podir=getattr(self,'podir','po') - podirnode=self.path.find_dir(podir) - if not podirnode: - error("could not find the podir %r"%podir) - continue - cache=getattr(self,'intlcache','.intlcache') - self.env['INTLCACHE']=os.path.join(self.path.bldpath(),podir,cache) - self.env['INTLPODIR']=podirnode.bldpath() - self.env['INTLFLAGS']=getattr(self,'flags',['-q','-u','-c']) task=self.create_task('intltool',node,node.change_ext('')) - inst=getattr(self,'install_path','${LOCALEDIR}') + inst=getattr(self,'install_path',None) if inst: self.bld.install_files(inst,task.outputs) @feature('intltool_po') def apply_intltool_po(self): try:self.meths.remove('process_source') except ValueError:pass - if not self.env.LOCALEDIR: - self.env.LOCALEDIR=self.env.PREFIX+'/share/locale' - appname=getattr(self,'appname','set_your_app_name') - podir=getattr(self,'podir','') + self.ensure_localedir() + appname=getattr(self,'appname',getattr(Context.g_module,Context.APPNAME,'set_your_app_name')) + podir=getattr(self,'podir','.') inst=getattr(self,'install_path','${LOCALEDIR}') linguas=self.path.find_node(os.path.join(podir,'LINGUAS')) if linguas: @@ -62,16 +78,20 @@ class po(Task.Task): run_str='${MSGFMT} -o ${TGT} ${SRC}' color='BLUE' class intltool(Task.Task): - run_str='${INTLTOOL} ${INTLFLAGS} ${INTLCACHE} ${INTLPODIR} ${SRC} ${TGT}' + run_str='${INTLTOOL} ${INTLFLAGS} ${INTLCACHE_ST:INTLCACHE} ${INTLPODIR} ${SRC} ${TGT}' color='BLUE' -def configure(conf): +@conf +def find_msgfmt(conf): conf.find_program('msgfmt',var='MSGFMT') - conf.find_perl_program('intltool-merge',var='INTLTOOL') - prefix=conf.env.PREFIX - datadir=conf.env.DATADIR - if not datadir: - datadir=os.path.join(prefix,'share') - conf.define('LOCALEDIR',os.path.join(datadir,'locale').replace('\\','\\\\')) - conf.define('DATADIR',datadir.replace('\\','\\\\')) +@conf +def find_intltool_merge(conf): + if not conf.env.PERL: + conf.find_program('perl',var='PERL') + conf.env.INTLCACHE_ST='--cache=%s' + conf.env.INTLFLAGS_DEFAULT=['-q','-u'] + conf.find_program('intltool-merge',interpreter='PERL',var='INTLTOOL') +def configure(conf): + conf.find_msgfmt() + conf.find_intltool_merge() if conf.env.CC or conf.env.CXX: conf.check(header_name='locale.h') diff --git a/waflib/Tools/irixcc.py b/waflib/Tools/irixcc.py index 8dbdfcae..24e98223 100644 --- a/waflib/Tools/irixcc.py +++ b/waflib/Tools/irixcc.py @@ -14,7 +14,6 @@ def find_irixcc(conf): elif'CC'in conf.environ:cc=conf.environ['CC'] if not cc:cc=conf.find_program('cc',var='CC') if not cc:conf.fatal('irixcc was not found') - cc=conf.cmd_to_list(cc) try: conf.cmd_and_log(cc+['-version']) except Exception: diff --git a/waflib/Tools/javaw.py b/waflib/Tools/javaw.py index 15f128c1..44c2b60c 100644 --- a/waflib/Tools/javaw.py +++ b/waflib/Tools/javaw.py @@ -157,7 +157,6 @@ class jar_create(Task.Task): return super(jar_create,self).runnable_status() class javac(Task.Task): color='BLUE' - nocache=True vars=['CLASSPATH','JAVACFLAGS','JAVAC','OUTDIR'] def runnable_status(self): for t in self.run_after: @@ -253,7 +252,6 @@ def configure(self): self.env['JAVA_HOME']=[self.environ['JAVA_HOME']] for x in'javac java jar javadoc'.split(): self.find_program(x,var=x.upper(),path_list=java_path) - self.env[x.upper()]=self.cmd_to_list(self.env[x.upper()]) if'CLASSPATH'in self.environ: v['CLASSPATH']=self.environ['CLASSPATH'] if not v['JAR']:self.fatal('jar is required for making java packages') diff --git a/waflib/Tools/kde4.py b/waflib/Tools/kde4.py index cd51f5f7..ee8ce48e 100644 --- a/waflib/Tools/kde4.py +++ b/waflib/Tools/kde4.py @@ -19,7 +19,7 @@ class msgfmt(Task.Task): run_str='${MSGFMT} ${SRC} -o ${TGT}' def configure(self): kdeconfig=self.find_program('kde4-config') - prefix=self.cmd_and_log('%s --prefix'%kdeconfig).strip() + prefix=self.cmd_and_log(kdeconfig+['--prefix']).strip() fname='%s/share/apps/cmake/modules/KDELibsDependencies.cmake'%prefix try:os.stat(fname) except OSError: @@ -28,7 +28,7 @@ def configure(self): except OSError:self.fatal('could not open %s'%fname) try: txt=Utils.readf(fname) - except(OSError,IOError): + except EnvironmentError: self.fatal('could not read %s'%fname) txt=txt.replace('\\\n','\n') fu=re.compile('#(.*)\n') diff --git a/waflib/Tools/ldc2.py b/waflib/Tools/ldc2.py index 25b99e53..d98f26e8 100644 --- a/waflib/Tools/ldc2.py +++ b/waflib/Tools/ldc2.py @@ -8,7 +8,7 @@ from waflib.Configure import conf @conf def find_ldc2(conf): conf.find_program(['ldc2'],var='D') - out=conf.cmd_and_log([conf.env.D,'-version']) + out=conf.cmd_and_log(conf.env.D+['-version']) if out.find("based on DMD v2.")==-1: conf.fatal("detected compiler is not ldc2") @conf diff --git a/waflib/Tools/msvc.py b/waflib/Tools/msvc.py index dd62e402..82d7d564 100644 --- a/waflib/Tools/msvc.py +++ b/waflib/Tools/msvc.py @@ -59,7 +59,11 @@ def setup_msvc(conf,versions,arch=False): @conf def get_msvc_version(conf,compiler,version,target,vcvars): debug('msvc: get_msvc_version: %r %r %r',compiler,version,target) - batfile=conf.bldnode.make_node('waf-print-msvc.bat') + try: + conf.msvc_cnt+=1 + except AttributeError: + conf.msvc_cnt=1 + batfile=conf.bldnode.make_node('waf-print-msvc-%d.bat'%conf.msvc_cnt) batfile.write("""@echo off set INCLUDE= set LIB= @@ -68,7 +72,7 @@ echo PATH=%%PATH%% echo INCLUDE=%%INCLUDE%% echo LIB=%%LIB%%;%%LIBPATH%% """%(vcvars,target)) - sout=conf.cmd_and_log(['cmd','/E:on','/V:on','/C',batfile.abspath()]) + sout=conf.cmd_and_log(['cmd.exe','/E:on','/V:on','/C',batfile.abspath()]) lines=sout.splitlines() if not lines[0]: lines.pop(0) @@ -87,7 +91,6 @@ echo LIB=%%LIB%%;%%LIBPATH%% env.update(PATH=path) compiler_name,linker_name,lib_name=_get_prog_names(conf,compiler) cxx=conf.find_program(compiler_name,path_list=MSVC_PATH) - cxx=conf.cmd_to_list(cxx) if'CL'in env: del(env['CL']) try: @@ -175,7 +178,7 @@ def gather_wince_supported_platforms(): def gather_msvc_detected_versions(): version_pattern=re.compile('^(\d\d?\.\d\d?)(Exp)?$') detected_versions=[] - for vcver,vcvar in[('VCExpress','Exp'),('VisualStudio','')]: + for vcver,vcvar in(('VCExpress','Exp'),('VisualStudio','')): try: prefix='SOFTWARE\\Wow6432node\\Microsoft\\'+vcver all_versions=Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE,prefix) @@ -372,7 +375,7 @@ def gather_intel_composer_versions(conf,versions): setattr(conf,compilervars_warning_attr,False) patch_url='http://software.intel.com/en-us/forums/topic/328487' compilervars_arch=os.path.join(path,'bin','compilervars_arch.bat') - for vscomntool in['VS110COMNTOOLS','VS100COMNTOOLS']: + for vscomntool in('VS110COMNTOOLS','VS100COMNTOOLS'): if vscomntool in os.environ: vs_express_path=os.environ[vscomntool]+r'..\IDE\VSWinExpress.exe' dev_env_path=os.environ[vscomntool]+r'..\IDE\devenv.exe' @@ -528,7 +531,6 @@ def find_msvc(conf): if v['CXX']:cxx=v['CXX'] elif'CXX'in conf.environ:cxx=conf.environ['CXX'] cxx=conf.find_program(compiler_name,var='CXX',path_list=path) - cxx=conf.cmd_to_list(cxx) env=dict(conf.environ) if path:env.update(PATH=';'.join(path)) if not conf.cmd_and_log(cxx+['/nologo','/help'],env=env): @@ -618,10 +620,8 @@ def apply_flags_msvc(self): if d[1:]=='debug': pdbnode=self.link_task.outputs[0].change_ext('.pdb') self.link_task.outputs.append(pdbnode) - try: - self.install_task.source.append(pdbnode) - except AttributeError: - pass + if getattr(self,'install_task',None): + self.pdb_install_task=self.bld.install_files(self.install_task.dest,pdbnode,env=self.env) break @feature('cprogram','cshlib','cxxprogram','cxxshlib') @after_method('apply_link') @@ -651,13 +651,11 @@ def exec_mf(self): elif'cshlib'in self.generator.features or'cxxshlib'in self.generator.features: mode='2' debug('msvc: embedding manifest in mode %r'%mode) - lst=[] - lst.append(env['MT']) + lst=[]+mtool lst.extend(Utils.to_list(env['MTFLAGS'])) lst.extend(['-manifest',manifest]) lst.append('-outputresource:%s;%s'%(outfile,mode)) - lst=[lst] - return self.exec_command(*lst) + return self.exec_command(lst) def quote_response_command(self,flag): if flag.find(' ')>-1: for x in('/LIBPATH:','/IMPLIB:','/OUT:','/I'): @@ -725,6 +723,8 @@ def wrap_class(class_name): derived_class.quote_response_command=quote_response_command derived_class.exec_command_msvc=exec_command_msvc derived_class.exec_mf=exec_mf + if hasattr(cls,'hcode'): + derived_class.hcode=cls.hcode return derived_class for k in'c cxx cprogram cxxprogram cshlib cxxshlib cstlib cxxstlib'.split(): wrap_class(k) diff --git a/waflib/Tools/perl.py b/waflib/Tools/perl.py index 8b6c2f80..87b6d93e 100644 --- a/waflib/Tools/perl.py +++ b/waflib/Tools/perl.py @@ -36,7 +36,7 @@ def check_perl_version(self,minver=None): self.end_msg("Perl not found",color="YELLOW") return False self.env['PERL']=perl - version=self.cmd_and_log([perl,"-e",'printf \"%vd\", $^V']) + version=self.cmd_and_log(self.env.PERL+["-e",'printf \"%vd\", $^V']) if not version: res=False version="Unknown" @@ -48,7 +48,7 @@ def check_perl_version(self,minver=None): return res @conf def check_perl_module(self,module): - cmd=[self.env['PERL'],'-e','use %s'%module] + cmd=self.env.PERL+['-e','use %s'%module] self.start_msg('perl module %s'%module) try: r=self.cmd_and_log(cmd) @@ -63,18 +63,22 @@ def check_perl_ext_devel(self): perl=env.PERL if not perl: self.fatal('find perl first') - def read_out(cmd): - return Utils.to_list(self.cmd_and_log(perl+cmd)) - env['LINKFLAGS_PERLEXT']=read_out(" -MConfig -e'print $Config{lddlflags}'") - env['INCLUDES_PERLEXT']=read_out(" -MConfig -e'print \"$Config{archlib}/CORE\"'") - env['CFLAGS_PERLEXT']=read_out(" -MConfig -e'print \"$Config{ccflags} $Config{cccdlflags}\"'") - env['XSUBPP']=read_out(" -MConfig -e'print \"$Config{privlib}/ExtUtils/xsubpp$Config{exe_ext}\"'") - env['EXTUTILS_TYPEMAP']=read_out(" -MConfig -e'print \"$Config{privlib}/ExtUtils/typemap\"'") + def cmd_perl_config(s): + return perl+['-MConfig','-e','print \"%s\"'%s] + def cfg_str(cfg): + return self.cmd_and_log(cmd_perl_config(cfg)) + def cfg_lst(cfg): + return Utils.to_list(cfg_str(cfg)) + env['LINKFLAGS_PERLEXT']=cfg_lst('$Config{lddlflags}') + env['INCLUDES_PERLEXT']=cfg_lst('$Config{archlib}/CORE') + env['CFLAGS_PERLEXT']=cfg_lst('$Config{ccflags} $Config{cccdlflags}') + env['XSUBPP']=cfg_lst('$Config{privlib}/ExtUtils/xsubpp$Config{exe_ext}') + env['EXTUTILS_TYPEMAP']=cfg_lst('$Config{privlib}/ExtUtils/typemap') if not getattr(Options.options,'perlarchdir',None): - env['ARCHDIR_PERL']=self.cmd_and_log(perl+" -MConfig -e'print $Config{sitearch}'") + env['ARCHDIR_PERL']=cfg_str('$Config{sitearch}') else: env['ARCHDIR_PERL']=getattr(Options.options,'perlarchdir') - env['perlext_PATTERN']='%s.'+self.cmd_and_log(perl+" -MConfig -e'print $Config{dlext}'") + env['perlext_PATTERN']='%s.'+cfg_str('$Config{dlext}') def options(opt): opt.add_option('--with-perl-binary',type='string',dest='perlbinary',help='Specify alternate perl binary',default=None) opt.add_option('--with-perl-archdir',type='string',dest='perlarchdir',help='Specify directory where to install arch specific files',default=None) diff --git a/waflib/Tools/python.py b/waflib/Tools/python.py index 56c0d7db..3cbaca15 100644 --- a/waflib/Tools/python.py +++ b/waflib/Tools/python.py @@ -3,7 +3,7 @@ # WARNING! Do not edit! http://waf.googlecode.com/git/docs/wafbook/single.html#_obtaining_the_waf_file import os,sys -from waflib import Utils,Options,Errors,Logs +from waflib import Utils,Options,Errors,Logs,Task,Node from waflib.TaskGen import extension,before_method,after_method,feature from waflib.Configure import conf FRAG=''' @@ -26,64 +26,66 @@ int main(int argc, char **argv) ''' INST=''' import sys, py_compile -py_compile.compile(sys.argv[1], sys.argv[2], sys.argv[3]) +py_compile.compile(sys.argv[1], sys.argv[2], sys.argv[3], True) ''' DISTUTILS_IMP=['from distutils.sysconfig import get_config_var, get_python_lib'] -@extension('.py') -def process_py(self,node): - try: - if not self.bld.is_install: - return - except AttributeError: - return - try: - if not self.install_path: - return - except AttributeError: - self.install_path='${PYTHONDIR}' - def inst_py(ctx): - install_from=getattr(self,'install_from',None) - if install_from: - install_from=self.path.find_dir(install_from) - install_pyfile(self,node,install_from) - self.bld.add_post_fun(inst_py) -def install_pyfile(self,node,install_from=None): - from_node=install_from or node.parent - tsk=self.bld.install_as(self.install_path+'/'+node.path_from(from_node),node,postpone=False) - path=tsk.get_install_path() - if self.bld.is_install<0: - Logs.info("+ removing byte compiled python files") - for x in'co': - try: - os.remove(path+x) - except OSError: - pass - if self.bld.is_install>0: - try: - st1=os.stat(path) - except OSError: - Logs.error('The python file is missing, this should not happen') - for x in['c','o']: - do_inst=self.env['PY'+x.upper()] - try: - st2=os.stat(path+x) - except OSError: - pass - else: - if st1.st_mtime<=st2.st_mtime: - do_inst=False - if do_inst: - lst=(x=='o')and[self.env['PYFLAGS_OPT']]or[] - (a,b,c)=(path,path+x,tsk.get_install_path(destdir=False)+x) - argv=self.env['PYTHON']+lst+['-c',INST,a,b,c] - Logs.info('+ byte compiling %r'%(path+x)) - env=self.env.env or None - ret=Utils.subprocess.Popen(argv,env=env).wait() - if ret: - raise Errors.WafError('py%s compilation failed %r'%(x,path)) +@before_method('process_source') @feature('py') def feature_py(self): - pass + self.install_path=getattr(self,'install_path','${PYTHONDIR}') + install_from=getattr(self,'install_from',None) + if install_from and not isinstance(install_from,Node.Node): + install_from=self.path.find_dir(install_from) + self.install_from=install_from + ver=self.env.PYTHON_VERSION + if not ver: + self.bld.fatal('Installing python files requires PYTHON_VERSION, try conf.check_python_version') + if int(ver.replace('.',''))>31: + self.install_32=True +@extension('.py') +def process_py(self,node): + assert(node.get_bld_sig()) + assert(getattr(self,'install_path')),'add features="py"' + if self.install_path: + if self.install_from: + self.bld.install_files(self.install_path,[node],cwd=self.install_from,relative_trick=True) + else: + self.bld.install_files(self.install_path,[node],relative_trick=True) + lst=[] + if self.env.PYC: + lst.append('pyc') + if self.env.PYO: + lst.append('pyo') + if self.install_path: + if self.install_from: + pyd=Utils.subst_vars("%s/%s"%(self.install_path,node.path_from(self.install_from)),self.env) + else: + pyd=Utils.subst_vars("%s/%s"%(self.install_path,node.path_from(self.path)),self.env) + else: + pyd=node.abspath() + for ext in lst: + if self.env.PYTAG: + name=node.name[:-3] + pyobj=node.parent.get_bld().make_node('__pycache__').make_node("%s.%s.%s"%(name,self.env.PYTAG,ext)) + pyobj.parent.mkdir() + else: + pyobj=node.change_ext(".%s"%ext) + tsk=self.create_task(ext,node,pyobj) + tsk.pyd=pyd + if self.install_path: + self.bld.install_files(os.path.dirname(pyd),pyobj,cwd=node.parent.get_bld(),relative_trick=True) +class pyc(Task.Task): + color='PINK' + def run(self): + cmd=[Utils.subst_vars('${PYTHON}',self.env),'-c',INST,self.inputs[0].abspath(),self.outputs[0].abspath(),self.pyd] + ret=self.generator.bld.exec_command(cmd) + return ret +class pyo(Task.Task): + color='PINK' + def run(self): + cmd=[Utils.subst_vars('${PYTHON}',self.env),Utils.subst_vars('${PYFLAGS_OPT}',self.env),'-c',INST,self.inputs[0].abspath(),self.outputs[0].abspath(),self.pyd] + ret=self.generator.bld.exec_command(cmd) + return ret @feature('pyext') @before_method('propagate_uselib_vars','apply_link') @after_method('apply_bundle') @@ -131,7 +133,7 @@ def get_python_variables(self,variables,imports=None): self.fatal('The distutils module is unusable: install "python-devel"?') self.to_log(out) return_values=[] - for s in out.split('\n'): + for s in out.splitlines(): s=s.strip() if not s: continue @@ -144,33 +146,82 @@ def get_python_variables(self,variables,imports=None): else:break return return_values @conf -def check_python_headers(conf): +def python_cross_compile(self,features='pyembed pyext'): + features=Utils.to_list(features) + if not('PYTHON_LDFLAGS'in self.environ or'PYTHON_PYEXT_LDFLAGS'in self.environ or'PYTHON_PYEMBED_LDFLAGS'in self.environ): + return False + for x in'PYTHON_VERSION PYTAG pyext_PATTERN'.split(): + if not x in self.environ: + self.fatal('Please set %s in the os environment'%x) + else: + self.env[x]=self.environ[x] + xx=self.env.CXX_NAME and'cxx'or'c' + if'pyext'in features: + flags=self.environ.get('PYTHON_PYEXT_LDFLAGS',self.environ.get('PYTHON_LDFLAGS',None)) + if flags is None: + self.fatal('No flags provided through PYTHON_PYEXT_LDFLAGS as required') + else: + self.parse_flags(flags,'PYEXT') + self.check(header_name='Python.h',define_name='HAVE_PYEXT',msg='Testing pyext configuration',features='%s %sshlib pyext'%(xx,xx),fragment=FRAG,errmsg='Could not build python extensions') + if'pyembed'in features: + flags=self.environ.get('PYTHON_PYEMBED_LDFLAGS',self.environ.get('PYTHON_LDFLAGS',None)) + if flags is None: + self.fatal('No flags provided through PYTHON_PYEMBED_LDFLAGS as required') + else: + self.parse_flags(flags,'PYEMBED') + self.check(header_name='Python.h',define_name='HAVE_PYEMBED',msg='Testing pyembed configuration',fragment=FRAG,errmsg='Could not build a python embedded interpreter',features='%s %sprogram pyembed'%(xx,xx)) + return True +@conf +def check_python_headers(conf,features='pyembed pyext'): + features=Utils.to_list(features) + assert('pyembed'in features)or('pyext'in features),"check_python_headers features must include 'pyembed' and/or 'pyext'" env=conf.env if not env['CC_NAME']and not env['CXX_NAME']: conf.fatal('load a compiler first (gcc, g++, ..)') + if conf.python_cross_compile(features): + return if not env['PYTHON_VERSION']: conf.check_python_version() - pybin=conf.env.PYTHON + pybin=env.PYTHON if not pybin: conf.fatal('Could not find the python executable') - v='prefix SO LDFLAGS LIBDIR LIBPL INCLUDEPY Py_ENABLE_SHARED MACOSX_DEPLOYMENT_TARGET LDSHARED CFLAGS'.split() + v='prefix SO LDFLAGS LIBDIR LIBPL INCLUDEPY Py_ENABLE_SHARED MACOSX_DEPLOYMENT_TARGET LDSHARED CFLAGS LDVERSION'.split() try: lst=conf.get_python_variables(["get_config_var('%s') or ''"%x for x in v]) except RuntimeError: conf.fatal("Python development headers not found (-v for details).") vals=['%s = %r'%(x,y)for(x,y)in zip(v,lst)] - conf.to_log("Configuration returned from %r:\n%r\n"%(pybin,'\n'.join(vals))) + conf.to_log("Configuration returned from %r:\n%s\n"%(pybin,'\n'.join(vals))) dct=dict(zip(v,lst)) x='MACOSX_DEPLOYMENT_TARGET' if dct[x]: - conf.env[x]=conf.environ[x]=dct[x] + env[x]=conf.environ[x]=dct[x] env['pyext_PATTERN']='%s'+dct['SO'] + num='.'.join(env['PYTHON_VERSION'].split('.')[:2]) + conf.find_program([''.join(pybin)+'-config','python%s-config'%num,'python-config-%s'%num,'python%sm-config'%num],var='PYTHON_CONFIG',msg="python-config",mandatory=False) + if env.PYTHON_CONFIG: + all_flags=[['--cflags','--libs','--ldflags']] + if sys.hexversion<0x2070000: + all_flags=[[k]for k in all_flags[0]] + xx=env.CXX_NAME and'cxx'or'c' + if'pyembed'in features: + for flags in all_flags: + conf.check_cfg(msg='Asking python-config for pyembed %r flags'%' '.join(flags),path=env.PYTHON_CONFIG,package='',uselib_store='PYEMBED',args=flags) + conf.check(header_name='Python.h',define_name='HAVE_PYEMBED',msg='Getting pyembed flags from python-config',fragment=FRAG,errmsg='Could not build a python embedded interpreter',features='%s %sprogram pyembed'%(xx,xx)) + if'pyext'in features: + for flags in all_flags: + conf.check_cfg(msg='Asking python-config for pyext %r flags'%' '.join(flags),path=env.PYTHON_CONFIG,package='',uselib_store='PYEXT',args=flags) + conf.check(header_name='Python.h',define_name='HAVE_PYEXT',msg='Getting pyext flags from python-config',features='%s %sshlib pyext'%(xx,xx),fragment=FRAG,errmsg='Could not build python extensions') + conf.define('HAVE_PYTHON_H',1) + return all_flags=dct['LDFLAGS']+' '+dct['CFLAGS'] conf.parse_flags(all_flags,'PYEMBED') all_flags=dct['LDFLAGS']+' '+dct['LDSHARED']+' '+dct['CFLAGS'] conf.parse_flags(all_flags,'PYEXT') result=None - for name in('python'+env['PYTHON_VERSION'],'python'+env['PYTHON_VERSION']+'m','python'+env['PYTHON_VERSION'].replace('.','')): + if not dct["LDVERSION"]: + dct["LDVERSION"]=env['PYTHON_VERSION'] + for name in('python'+dct['LDVERSION'],'python'+env['PYTHON_VERSION']+'m','python'+env['PYTHON_VERSION'].replace('.','')): if not result and env['LIBPATH_PYEMBED']: path=env['LIBPATH_PYEMBED'] conf.to_log("\n\n# Trying default LIBPATH_PYEMBED: %r\n"%path) @@ -194,25 +245,12 @@ def check_python_headers(conf): env.append_value('LIB_PYEMBED',[name]) else: conf.to_log("\n\n### LIB NOT FOUND\n") - if(Utils.is_win32 or sys.platform.startswith('os2')or dct['Py_ENABLE_SHARED']): + if Utils.is_win32 or dct['Py_ENABLE_SHARED']: env['LIBPATH_PYEXT']=env['LIBPATH_PYEMBED'] env['LIB_PYEXT']=env['LIB_PYEMBED'] - num='.'.join(env['PYTHON_VERSION'].split('.')[:2]) - conf.find_program([''.join(pybin)+'-config','python%s-config'%num,'python-config-%s'%num,'python%sm-config'%num],var='PYTHON_CONFIG',mandatory=False) - includes=[] - if conf.env.PYTHON_CONFIG: - for incstr in conf.cmd_and_log([conf.env.PYTHON_CONFIG,'--includes']).strip().split(): - if(incstr.startswith('-I')or incstr.startswith('/I')): - incstr=incstr[2:] - if incstr not in includes: - includes.append(incstr) - conf.to_log("Include path for Python extensions (found via python-config --includes): %r\n"%(includes,)) - env['INCLUDES_PYEXT']=includes - env['INCLUDES_PYEMBED']=includes - else: - conf.to_log("Include path for Python extensions ""(found via distutils module): %r\n"%(dct['INCLUDEPY'],)) - env['INCLUDES_PYEXT']=[dct['INCLUDEPY']] - env['INCLUDES_PYEMBED']=[dct['INCLUDEPY']] + conf.to_log("Include path for Python extensions (found via distutils module): %r\n"%(dct['INCLUDEPY'],)) + env['INCLUDES_PYEXT']=[dct['INCLUDEPY']] + env['INCLUDES_PYEMBED']=[dct['INCLUDEPY']] if env['CC_NAME']=='gcc': env.append_value('CFLAGS_PYEMBED',['-fno-strict-aliasing']) env.append_value('CFLAGS_PYEXT',['-fno-strict-aliasing']) @@ -226,17 +264,7 @@ def check_python_headers(conf): env.append_value('CFLAGS_PYEXT',dist_compiler.compile_options) env.append_value('CXXFLAGS_PYEXT',dist_compiler.compile_options) env.append_value('LINKFLAGS_PYEXT',dist_compiler.ldflags_shared) - try: - conf.check(header_name='Python.h',define_name='HAVE_PYTHON_H',uselib='PYEMBED',fragment=FRAG,errmsg=':-(') - except conf.errors.ConfigurationError: - xx=conf.env.CXX_NAME and'cxx'or'c' - flags=['--cflags','--libs','--ldflags'] - for f in flags: - conf.check_cfg(msg='Asking python-config for pyembed %s flags'%f,path=conf.env.PYTHON_CONFIG,package='',uselib_store='PYEMBED',args=[f]) - conf.check(header_name='Python.h',define_name='HAVE_PYTHON_H',msg='Getting pyembed flags from python-config',fragment=FRAG,errmsg='Could not build a python embedded interpreter',features='%s %sprogram pyembed'%(xx,xx)) - for f in flags: - conf.check_cfg(msg='Asking python-config for pyext %s flags'%f,path=conf.env.PYTHON_CONFIG,package='',uselib_store='PYEXT',args=[f]) - conf.check(header_name='Python.h',define_name='HAVE_PYTHON_H',msg='Getting pyext flags from python-config',features='%s %sshlib pyext'%(xx,xx),fragment=FRAG,errmsg='Could not build python extensions') + conf.check(header_name='Python.h',define_name='HAVE_PYTHON_H',uselib='PYEMBED',fragment=FRAG,errmsg='Distutils not installed? Broken python installation? Get python-config now!') @conf def check_python_version(conf,minver=None): assert minver is None or isinstance(minver,tuple) @@ -252,23 +280,27 @@ def check_python_version(conf,minver=None): if result: pyver='.'.join([str(x)for x in pyver_tuple[:2]]) conf.env['PYTHON_VERSION']=pyver - if'PYTHONDIR'in conf.environ: + if'PYTHONDIR'in conf.env: + pydir=conf.env['PYTHONDIR'] + elif'PYTHONDIR'in conf.environ: pydir=conf.environ['PYTHONDIR'] else: if Utils.is_win32: - (python_LIBDEST,pydir)=conf.get_python_variables(["get_config_var('LIBDEST') or ''","get_python_lib(standard_lib=0, prefix=%r) or ''"%conf.env['PREFIX']]) + (python_LIBDEST,pydir)=conf.get_python_variables(["get_config_var('LIBDEST') or ''","get_python_lib(standard_lib=0) or ''"]) else: python_LIBDEST=None - (pydir,)=conf.get_python_variables(["get_python_lib(standard_lib=0, prefix=%r) or ''"%conf.env['PREFIX']]) + (pydir,)=conf.get_python_variables(["get_python_lib(standard_lib=0) or ''"]) if python_LIBDEST is None: if conf.env['LIBDIR']: python_LIBDEST=os.path.join(conf.env['LIBDIR'],"python"+pyver) else: python_LIBDEST=os.path.join(conf.env['PREFIX'],"lib","python"+pyver) - if'PYTHONARCHDIR'in conf.environ: + if'PYTHONARCHDIR'in conf.env: + pyarchdir=conf.env['PYTHONARCHDIR'] + elif'PYTHONARCHDIR'in conf.environ: pyarchdir=conf.environ['PYTHONARCHDIR'] else: - (pyarchdir,)=conf.get_python_variables(["get_python_lib(plat_specific=1, standard_lib=0, prefix=%r) or ''"%conf.env['PREFIX']]) + (pyarchdir,)=conf.get_python_variables(["get_python_lib(plat_specific=1, standard_lib=0) or ''"]) if not pyarchdir: pyarchdir=pydir if hasattr(conf,'define'): @@ -288,13 +320,13 @@ PYTHON_MODULE_TEMPLATE=''' import %s as current_module version = getattr(current_module, '__version__', None) if version is not None: - print(str(version)) + print(str(version)) else: - print('unknown version') + print('unknown version') ''' @conf def check_python_module(conf,module_name,condition=''): - msg='Python module %s'%module_name + msg="Checking for python module '%s'"%module_name if condition: msg='%s (%s)'%(msg,condition) conf.start_msg(msg) @@ -324,20 +356,25 @@ def check_python_module(conf,module_name,condition=''): else: conf.end_msg(ret) def configure(conf): - try: - conf.find_program('python',var='PYTHON') - except conf.errors.ConfigurationError: - Logs.warn("could not find a python executable, setting to sys.executable '%s'"%sys.executable) - conf.env.PYTHON=sys.executable - if conf.env.PYTHON!=sys.executable: - Logs.warn("python executable %r differs from system %r"%(conf.env.PYTHON,sys.executable)) - conf.env.PYTHON=conf.cmd_to_list(conf.env.PYTHON) v=conf.env - v['PYCMD']='"import sys, py_compile;py_compile.compile(sys.argv[1], sys.argv[2])"' + v['PYTHON']=Options.options.python or os.environ.get('PYTHON',sys.executable) + if Options.options.pythondir: + v['PYTHONDIR']=Options.options.pythondir + if Options.options.pythonarchdir: + v['PYTHONARCHDIR']=Options.options.pythonarchdir + conf.find_program('python',var='PYTHON') v['PYFLAGS']='' v['PYFLAGS_OPT']='-O' v['PYC']=getattr(Options.options,'pyc',1) v['PYO']=getattr(Options.options,'pyo',1) + try: + v.PYTAG=conf.cmd_and_log(conf.env.PYTHON+['-c',"import imp;print(imp.get_tag())"]).strip() + except Errors.WafError: + pass def options(opt): - opt.add_option('--nopyc',action='store_false',default=1,help='Do not install bytecode compiled .pyc files (configuration) [Default:install]',dest='pyc') - opt.add_option('--nopyo',action='store_false',default=1,help='Do not install optimised compiled .pyo files (configuration) [Default:install]',dest='pyo') + pyopt=opt.add_option_group("Python Options") + pyopt.add_option('--nopyc',dest='pyc',action='store_false',default=1,help='Do not install bytecode compiled .pyc files (configuration) [Default:install]') + pyopt.add_option('--nopyo',dest='pyo',action='store_false',default=1,help='Do not install optimised compiled .pyo files (configuration) [Default:install]') + pyopt.add_option('--python',dest="python",help='python binary to be used [Default: %s]'%sys.executable) + pyopt.add_option('--pythondir',dest='pythondir',help='Installation path for python modules (py, platform-independent .py and .pyc files)') + pyopt.add_option('--pythonarchdir',dest='pythonarchdir',help='Installation path for python extension (pyext, platform-dependent .so or .dylib files)') diff --git a/waflib/Tools/qt4.py b/waflib/Tools/qt4.py index b4328e72..49cdf93c 100644 --- a/waflib/Tools/qt4.py +++ b/waflib/Tools/qt4.py @@ -11,8 +11,8 @@ except ImportError: else: has_xml=True import os,sys -from waflib.Tools import c_preproc,cxx -from waflib import Task,Utils,Options,Errors +from waflib.Tools import cxx +from waflib import Task,Utils,Options,Errors,Context from waflib.TaskGen import feature,after_method,extension from waflib.Configure import conf from waflib import Logs @@ -25,17 +25,6 @@ class qxx(Task.classes['cxx']): def __init__(self,*k,**kw): Task.Task.__init__(self,*k,**kw) self.moc_done=0 - def scan(self): - (nodes,names)=c_preproc.scan(self) - lst=[] - for x in nodes: - if x.name.endswith('.moc'): - s=x.path_from(self.inputs[0].parent.get_bld()) - if s not in names: - names.append(s) - else: - lst.append(x) - return(lst,names) def runnable_status(self): if self.moc_done: return Task.Task.runnable_status(self) @@ -56,10 +45,20 @@ class qxx(Task.classes['cxx']): tsk=moc_cache[h_node]=Task.classes['moc'](env=self.env,generator=self.generator) tsk.set_inputs(h_node) tsk.set_outputs(m_node) + if self.generator: + self.generator.tasks.append(tsk) gen=self.generator.bld.producer gen.outstanding.insert(0,tsk) gen.total+=1 return tsk + def moc_h_ext(self): + try: + ext=Options.options.qt_header_ext.split() + except AttributeError: + pass + if not ext: + ext=MOC_H + return ext def add_moc_tasks(self): node=self.inputs[0] bld=self.generator.bld @@ -69,27 +68,19 @@ class qxx(Task.classes['cxx']): pass else: delattr(self,'cache_sig') + include_nodes=[node.parent]+self.generator.includes_nodes moctasks=[] - mocfiles=[] - try: - tmp_lst=bld.raw_deps[self.uid()] - bld.raw_deps[self.uid()]=[] - except KeyError: - tmp_lst=[] - for d in tmp_lst: + mocfiles=set([]) + for d in bld.raw_deps.get(self.uid(),[]): if not d.endswith('.moc'): continue if d in mocfiles: - Logs.error("paranoia owns") continue - mocfiles.append(d) + mocfiles.add(d) h_node=None - try:ext=Options.options.qt_header_ext.split() - except AttributeError:pass - if not ext:ext=MOC_H base2=d[:-4] - for x in[node.parent]+self.generator.includes_nodes: - for e in ext: + for x in include_nodes: + for e in self.moc_h_ext(): h_node=x.find_node(base2+e) if h_node: break @@ -99,28 +90,19 @@ class qxx(Task.classes['cxx']): else: for k in EXT_QT4: if base2.endswith(k): - for x in[node.parent]+self.generator.includes_nodes: + for x in include_nodes: h_node=x.find_node(base2) if h_node: break - if h_node: - m_node=h_node.change_ext(k+'.moc') - break + if h_node: + m_node=h_node.change_ext(k+'.moc') + break if not h_node: - raise Errors.WafError('no header found for %r which is a moc file'%d) - bld.node_deps[(self.inputs[0].parent.abspath(),m_node.name)]=h_node + raise Errors.WafError('No source found for %r which is a moc file'%d) task=self.create_moc_task(h_node,m_node) moctasks.append(task) - tmp_lst=bld.raw_deps[self.uid()]=mocfiles - lst=bld.node_deps.get(self.uid(),()) - for d in lst: - name=d.name - if name.endswith('.moc'): - task=self.create_moc_task(bld.node_deps[(self.inputs[0].parent.abspath(),name)],d) - moctasks.append(task) self.run_after.update(set(moctasks)) self.moc_done=1 - run=Task.classes['cxx'].__dict__['run'] class trans_update(Task.Task): run_str='${QT_LUPDATE} ${SRC} -ts ${TGT}' color='BLUE' @@ -140,7 +122,7 @@ class XMLHandler(ContentHandler): @extension(*EXT_RCC) def create_rcc_task(self,node): rcnode=node.change_ext('_rc.cpp') - rcctask=self.create_task('rcc',node,rcnode) + self.create_task('rcc',node,rcnode) cpptask=self.create_task('cxx',rcnode,rcnode.change_ext('.o')) try: self.compiled_tasks.append(cpptask) @@ -179,7 +161,7 @@ def apply_qt4(self): for flag in self.to_list(self.env['CXXFLAGS']): if len(flag)<2:continue f=flag[0:2] - if f in['-D','-I','/D','/I']: + if f in('-D','-I','/D','/I'): if(f[0]=='/'): lst.append('-'+flag[1:]) else: @@ -190,10 +172,11 @@ def cxx_hook(self,node): return self.create_compiled_task('qxx',node) class rcc(Task.Task): color='BLUE' - run_str='${QT_RCC} -name ${SRC[0].name} ${SRC[0].abspath()} ${RCC_ST} -o ${TGT}' + run_str='${QT_RCC} -name ${tsk.rcname()} ${SRC[0].abspath()} ${RCC_ST} -o ${TGT}' ext_out=['.h'] + def rcname(self): + return os.path.splitext(self.inputs[0].name)[0] def scan(self): - node=self.inputs[0] if not has_xml: Logs.error('no xml support was found, the rcc dependencies will be incomplete!') return([],[]) @@ -216,6 +199,10 @@ class rcc(Task.Task): class moc(Task.Task): color='BLUE' run_str='${QT_MOC} ${MOC_FLAGS} ${MOCCPPPATH_ST:INCPATHS} ${MOCDEFINES_ST:DEFINES} ${SRC} ${MOC_ST} ${TGT}' + def keyword(self): + return"Creating" + def __str__(self): + return self.outputs[0].path_from(self.generator.bld.launch_node()) class ui4(Task.Task): color='BLUE' run_str='${QT_UIC} ${SRC} -o ${TGT}' @@ -267,14 +254,14 @@ def find_qt4_binaries(self): paths.append(qtbin) cand=None prev_ver=['4','0','0'] - for qmk in['qmake-qt4','qmake4','qmake']: + for qmk in('qmake-qt4','qmake4','qmake'): try: qmake=self.find_program(qmk,path_list=paths) except self.errors.ConfigurationError: pass else: try: - version=self.cmd_and_log([qmake,'-query','QT_VERSION']).strip() + version=self.cmd_and_log(qmake+['-query','QT_VERSION']).strip() except self.errors.WafError: pass else: @@ -287,7 +274,7 @@ def find_qt4_binaries(self): self.env.QMAKE=cand else: self.fatal('Could not find qmake for qt4') - qtbin=self.cmd_and_log([self.env.QMAKE,'-query','QT_INSTALL_BINS']).strip()+os.sep + qtbin=self.cmd_and_log(self.env.QMAKE+['-query','QT_INSTALL_BINS']).strip()+os.sep def find_bin(lst,var): if var in env: return @@ -301,18 +288,17 @@ def find_qt4_binaries(self): break find_bin(['uic-qt3','uic3'],'QT_UIC3') find_bin(['uic-qt4','uic'],'QT_UIC') - if not env['QT_UIC']: + if not env.QT_UIC: self.fatal('cannot find the uic compiler for qt4') - try: - uicver=self.cmd_and_log(env['QT_UIC']+" -version 2>&1").strip() - except self.errors.ConfigurationError: - self.fatal('this uic compiler is for qt3, add uic for qt4 to your path') + self.start_msg('Checking for uic version') + uicver=self.cmd_and_log(env.QT_UIC+["-version"],output=Context.BOTH) + uicver=''.join(uicver).strip() uicver=uicver.replace('Qt User Interface Compiler ','').replace('User Interface Compiler for Qt','') - self.msg('Checking for uic version','%s'%uicver) + self.end_msg(uicver) if uicver.find(' 3.')!=-1: self.fatal('this uic compiler is for qt3, add uic for qt4 to your path') find_bin(['moc-qt4','moc'],'QT_MOC') - find_bin(['rcc'],'QT_RCC') + find_bin(['rcc-qt4','rcc'],'QT_RCC') find_bin(['lrelease-qt4','lrelease'],'QT_LRELEASE') find_bin(['lupdate-qt4','lupdate'],'QT_LUPDATE') env['UIC3_ST']='%s -o %s' @@ -327,12 +313,12 @@ def find_qt4_libraries(self): qtlibs=getattr(Options.options,'qtlibs',None)or os.environ.get("QT4_LIBDIR",None) if not qtlibs: try: - qtlibs=self.cmd_and_log([self.env.QMAKE,'-query','QT_INSTALL_LIBS']).strip() + qtlibs=self.cmd_and_log(self.env.QMAKE+['-query','QT_INSTALL_LIBS']).strip() except Errors.WafError: - qtdir=self.cmd_and_log([self.env.QMAKE,'-query','QT_INSTALL_PREFIX']).strip()+os.sep + qtdir=self.cmd_and_log(self.env.QMAKE+['-query','QT_INSTALL_PREFIX']).strip()+os.sep qtlibs=os.path.join(qtdir,'lib') self.msg('Found the Qt4 libraries in',qtlibs) - qtincludes=os.environ.get("QT4_INCLUDES",None)or self.cmd_and_log([self.env.QMAKE,'-query','QT_INSTALL_HEADERS']).strip() + qtincludes=os.environ.get("QT4_INCLUDES",None)or self.cmd_and_log(self.env.QMAKE+['-query','QT_INSTALL_HEADERS']).strip() env=self.env if not'PKG_CONFIG_PATH'in os.environ: os.environ['PKG_CONFIG_PATH']='%s:%s/pkgconfig:/usr/lib/qt4/lib/pkgconfig:/opt/qt4/lib/pkgconfig:/usr/lib/qt4/lib:/opt/qt4/lib'%(qtlibs,qtlibs) diff --git a/waflib/Tools/qt5.py b/waflib/Tools/qt5.py new file mode 100644 index 00000000..8213b8dc --- /dev/null +++ b/waflib/Tools/qt5.py @@ -0,0 +1,488 @@ +#! /usr/bin/env python +# encoding: utf-8 +# WARNING! Do not edit! http://waf.googlecode.com/git/docs/wafbook/single.html#_obtaining_the_waf_file + +try: + from xml.sax import make_parser + from xml.sax.handler import ContentHandler +except ImportError: + has_xml=False + ContentHandler=object +else: + has_xml=True +import os,sys +from waflib.Tools import cxx +from waflib import Task,Utils,Options,Errors,Context +from waflib.TaskGen import feature,after_method,extension +from waflib.Configure import conf +from waflib import Logs +MOC_H=['.h','.hpp','.hxx','.hh'] +EXT_RCC=['.qrc'] +EXT_UI=['.ui'] +EXT_QT5=['.cpp','.cc','.cxx','.C'] +QT5_LIBS=''' +qtmain +Qt5Bluetooth +Qt5CLucene +Qt5Concurrent +Qt5Core +Qt5DBus +Qt5Declarative +Qt5DesignerComponents +Qt5Designer +Qt5Gui +Qt5Help +Qt5MultimediaQuick_p +Qt5Multimedia +Qt5MultimediaWidgets +Qt5Network +Qt5Nfc +Qt5OpenGL +Qt5Positioning +Qt5PrintSupport +Qt5Qml +Qt5QuickParticles +Qt5Quick +Qt5QuickTest +Qt5Script +Qt5ScriptTools +Qt5Sensors +Qt5SerialPort +Qt5Sql +Qt5Svg +Qt5Test +Qt5WebKit +Qt5WebKitWidgets +Qt5Widgets +Qt5WinExtras +Qt5X11Extras +Qt5XmlPatterns +Qt5Xml''' +class qxx(Task.classes['cxx']): + def __init__(self,*k,**kw): + Task.Task.__init__(self,*k,**kw) + self.moc_done=0 + def runnable_status(self): + if self.moc_done: + return Task.Task.runnable_status(self) + else: + for t in self.run_after: + if not t.hasrun: + return Task.ASK_LATER + self.add_moc_tasks() + return Task.Task.runnable_status(self) + def create_moc_task(self,h_node,m_node): + try: + moc_cache=self.generator.bld.moc_cache + except AttributeError: + moc_cache=self.generator.bld.moc_cache={} + try: + return moc_cache[h_node] + except KeyError: + tsk=moc_cache[h_node]=Task.classes['moc'](env=self.env,generator=self.generator) + tsk.set_inputs(h_node) + tsk.set_outputs(m_node) + if self.generator: + self.generator.tasks.append(tsk) + gen=self.generator.bld.producer + gen.outstanding.insert(0,tsk) + gen.total+=1 + return tsk + else: + delattr(self,'cache_sig') + def moc_h_ext(self): + try: + ext=Options.options.qt_header_ext.split() + except AttributeError: + pass + if not ext: + ext=MOC_H + return ext + def add_moc_tasks(self): + node=self.inputs[0] + bld=self.generator.bld + try: + self.signature() + except KeyError: + pass + else: + delattr(self,'cache_sig') + include_nodes=[node.parent]+self.generator.includes_nodes + moctasks=[] + mocfiles=set([]) + for d in bld.raw_deps.get(self.uid(),[]): + if not d.endswith('.moc'): + continue + if d in mocfiles: + continue + mocfiles.add(d) + h_node=None + base2=d[:-4] + for x in include_nodes: + for e in self.moc_h_ext(): + h_node=x.find_node(base2+e) + if h_node: + break + if h_node: + m_node=h_node.change_ext('.moc') + break + else: + for k in EXT_QT5: + if base2.endswith(k): + for x in include_nodes: + h_node=x.find_node(base2) + if h_node: + break + if h_node: + m_node=h_node.change_ext(k+'.moc') + break + if not h_node: + raise Errors.WafError('No source found for %r which is a moc file'%d) + task=self.create_moc_task(h_node,m_node) + moctasks.append(task) + self.run_after.update(set(moctasks)) + self.moc_done=1 +class trans_update(Task.Task): + run_str='${QT_LUPDATE} ${SRC} -ts ${TGT}' + color='BLUE' +Task.update_outputs(trans_update) +class XMLHandler(ContentHandler): + def __init__(self): + self.buf=[] + self.files=[] + def startElement(self,name,attrs): + if name=='file': + self.buf=[] + def endElement(self,name): + if name=='file': + self.files.append(str(''.join(self.buf))) + def characters(self,cars): + self.buf.append(cars) +@extension(*EXT_RCC) +def create_rcc_task(self,node): + rcnode=node.change_ext('_rc.cpp') + self.create_task('rcc',node,rcnode) + cpptask=self.create_task('cxx',rcnode,rcnode.change_ext('.o')) + try: + self.compiled_tasks.append(cpptask) + except AttributeError: + self.compiled_tasks=[cpptask] + return cpptask +@extension(*EXT_UI) +def create_uic_task(self,node): + uictask=self.create_task('ui5',node) + uictask.outputs=[self.path.find_or_declare(self.env['ui_PATTERN']%node.name[:-3])] +@extension('.ts') +def add_lang(self,node): + self.lang=self.to_list(getattr(self,'lang',[]))+[node] +@feature('qt5') +@after_method('apply_link') +def apply_qt5(self): + if getattr(self,'lang',None): + qmtasks=[] + for x in self.to_list(self.lang): + if isinstance(x,str): + x=self.path.find_resource(x+'.ts') + qmtasks.append(self.create_task('ts2qm',x,x.change_ext('.qm'))) + if getattr(self,'update',None)and Options.options.trans_qt5: + cxxnodes=[a.inputs[0]for a in self.compiled_tasks]+[a.inputs[0]for a in self.tasks if getattr(a,'inputs',None)and a.inputs[0].name.endswith('.ui')] + for x in qmtasks: + self.create_task('trans_update',cxxnodes,x.inputs) + if getattr(self,'langname',None): + qmnodes=[x.outputs[0]for x in qmtasks] + rcnode=self.langname + if isinstance(rcnode,str): + rcnode=self.path.find_or_declare(rcnode+'.qrc') + t=self.create_task('qm2rcc',qmnodes,rcnode) + k=create_rcc_task(self,t.outputs[0]) + self.link_task.inputs.append(k.outputs[0]) + lst=[] + for flag in self.to_list(self.env['CXXFLAGS']): + if len(flag)<2:continue + f=flag[0:2] + if f in('-D','-I','/D','/I'): + if(f[0]=='/'): + lst.append('-'+flag[1:]) + else: + lst.append(flag) + self.env.append_value('MOC_FLAGS',lst) +@extension(*EXT_QT5) +def cxx_hook(self,node): + return self.create_compiled_task('qxx',node) +class rcc(Task.Task): + color='BLUE' + run_str='${QT_RCC} -name ${tsk.rcname()} ${SRC[0].abspath()} ${RCC_ST} -o ${TGT}' + ext_out=['.h'] + def rcname(self): + return os.path.splitext(self.inputs[0].name)[0] + def scan(self): + if not has_xml: + Logs.error('no xml support was found, the rcc dependencies will be incomplete!') + return([],[]) + parser=make_parser() + curHandler=XMLHandler() + parser.setContentHandler(curHandler) + fi=open(self.inputs[0].abspath(),'r') + try: + parser.parse(fi) + finally: + fi.close() + nodes=[] + names=[] + root=self.inputs[0].parent + for x in curHandler.files: + nd=root.find_resource(x) + if nd:nodes.append(nd) + else:names.append(x) + return(nodes,names) +class moc(Task.Task): + color='BLUE' + run_str='${QT_MOC} ${MOC_FLAGS} ${MOCCPPPATH_ST:INCPATHS} ${MOCDEFINES_ST:DEFINES} ${SRC} ${MOC_ST} ${TGT}' +class ui5(Task.Task): + color='BLUE' + run_str='${QT_UIC} ${SRC} -o ${TGT}' + ext_out=['.h'] +class ts2qm(Task.Task): + color='BLUE' + run_str='${QT_LRELEASE} ${QT_LRELEASE_FLAGS} ${SRC} -qm ${TGT}' +class qm2rcc(Task.Task): + color='BLUE' + after='ts2qm' + def run(self): + txt='\n'.join(['%s'%k.path_from(self.outputs[0].parent)for k in self.inputs]) + code='\n\n%s\n\n'%txt + self.outputs[0].write(code) +def configure(self): + self.find_qt5_binaries() + self.set_qt5_libs_to_check() + self.set_qt5_defines() + self.find_qt5_libraries() + self.add_qt5_rpath() + self.simplify_qt5_libs() +@conf +def find_qt5_binaries(self): + env=self.env + opt=Options.options + qtdir=getattr(opt,'qtdir','') + qtbin=getattr(opt,'qtbin','') + paths=[] + if qtdir: + qtbin=os.path.join(qtdir,'bin') + if not qtdir: + qtdir=os.environ.get('QT5_ROOT','') + qtbin=os.environ.get('QT5_BIN',None)or os.path.join(qtdir,'bin') + if qtbin: + paths=[qtbin] + if not qtdir: + paths=os.environ.get('PATH','').split(os.pathsep) + paths.append('/usr/share/qt5/bin/') + try: + lst=Utils.listdir('/usr/local/Trolltech/') + except OSError: + pass + else: + if lst: + lst.sort() + lst.reverse() + qtdir='/usr/local/Trolltech/%s/'%lst[0] + qtbin=os.path.join(qtdir,'bin') + paths.append(qtbin) + cand=None + prev_ver=['5','0','0'] + for qmk in('qmake-qt5','qmake5','qmake'): + try: + qmake=self.find_program(qmk,path_list=paths) + except self.errors.ConfigurationError: + pass + else: + try: + version=self.cmd_and_log(qmake+['-query','QT_VERSION']).strip() + except self.errors.WafError: + pass + else: + if version: + new_ver=version.split('.') + if new_ver>prev_ver: + cand=qmake + prev_ver=new_ver + if not cand: + try: + self.find_program('qtchooser') + except self.errors.ConfigurationError: + pass + else: + cmd=self.env.QTCHOOSER+['-qt=5','-run-tool=qmake'] + try: + version=self.cmd_and_log(cmd+['-query','QT_VERSION']) + except self.errors.WafError: + pass + else: + cand=cmd + if cand: + self.env.QMAKE=cand + else: + self.fatal('Could not find qmake for qt5') + self.env.QT_INSTALL_BINS=qtbin=self.cmd_and_log(self.env.QMAKE+['-query','QT_INSTALL_BINS']).strip()+os.sep + paths.insert(0,qtbin) + def find_bin(lst,var): + if var in env: + return + for f in lst: + try: + ret=self.find_program(f,path_list=paths) + except self.errors.ConfigurationError: + pass + else: + env[var]=ret + break + find_bin(['uic-qt5','uic'],'QT_UIC') + if not env.QT_UIC: + self.fatal('cannot find the uic compiler for qt5') + self.start_msg('Checking for uic version') + uicver=self.cmd_and_log(env.QT_UIC+['-version'],output=Context.BOTH) + uicver=''.join(uicver).strip() + uicver=uicver.replace('Qt User Interface Compiler ','').replace('User Interface Compiler for Qt','') + self.end_msg(uicver) + if uicver.find(' 3.')!=-1 or uicver.find(' 4.')!=-1: + self.fatal('this uic compiler is for qt3 or qt5, add uic for qt5 to your path') + find_bin(['moc-qt5','moc'],'QT_MOC') + find_bin(['rcc-qt5','rcc'],'QT_RCC') + find_bin(['lrelease-qt5','lrelease'],'QT_LRELEASE') + find_bin(['lupdate-qt5','lupdate'],'QT_LUPDATE') + env['UIC_ST']='%s -o %s' + env['MOC_ST']='-o' + env['ui_PATTERN']='ui_%s.h' + env['QT_LRELEASE_FLAGS']=['-silent'] + env.MOCCPPPATH_ST='-I%s' + env.MOCDEFINES_ST='-D%s' +@conf +def find_qt5_libraries(self): + qtlibs=getattr(Options.options,'qtlibs',None)or os.environ.get("QT5_LIBDIR",None) + if not qtlibs: + try: + qtlibs=self.cmd_and_log(self.env.QMAKE+['-query','QT_INSTALL_LIBS']).strip() + except Errors.WafError: + qtdir=self.cmd_and_log(self.env.QMAKE+['-query','QT_INSTALL_PREFIX']).strip()+os.sep + qtlibs=os.path.join(qtdir,'lib') + self.msg('Found the Qt5 libraries in',qtlibs) + qtincludes=os.environ.get("QT5_INCLUDES",None)or self.cmd_and_log(self.env.QMAKE+['-query','QT_INSTALL_HEADERS']).strip() + env=self.env + if not'PKG_CONFIG_PATH'in os.environ: + os.environ['PKG_CONFIG_PATH']='%s:%s/pkgconfig:/usr/lib/qt5/lib/pkgconfig:/opt/qt5/lib/pkgconfig:/usr/lib/qt5/lib:/opt/qt5/lib'%(qtlibs,qtlibs) + try: + if os.environ.get("QT5_XCOMPILE",None): + raise self.errors.ConfigurationError() + self.check_cfg(atleast_pkgconfig_version='0.1') + except self.errors.ConfigurationError: + for i in self.qt5_vars: + uselib=i.upper() + if Utils.unversioned_sys_platform()=="darwin": + frameworkName=i+".framework" + qtDynamicLib=os.path.join(qtlibs,frameworkName,i) + if os.path.exists(qtDynamicLib): + env.append_unique('FRAMEWORK_'+uselib,i) + self.msg('Checking for %s'%i,qtDynamicLib,'GREEN') + else: + self.msg('Checking for %s'%i,False,'YELLOW') + env.append_unique('INCLUDES_'+uselib,os.path.join(qtlibs,frameworkName,'Headers')) + elif env.DEST_OS!="win32": + qtDynamicLib=os.path.join(qtlibs,"lib"+i+".so") + qtStaticLib=os.path.join(qtlibs,"lib"+i+".a") + if os.path.exists(qtDynamicLib): + env.append_unique('LIB_'+uselib,i) + self.msg('Checking for %s'%i,qtDynamicLib,'GREEN') + elif os.path.exists(qtStaticLib): + env.append_unique('LIB_'+uselib,i) + self.msg('Checking for %s'%i,qtStaticLib,'GREEN') + else: + self.msg('Checking for %s'%i,False,'YELLOW') + env.append_unique('LIBPATH_'+uselib,qtlibs) + env.append_unique('INCLUDES_'+uselib,qtincludes) + env.append_unique('INCLUDES_'+uselib,os.path.join(qtincludes,i)) + else: + for k in("lib%s.a","lib%s5.a","%s.lib","%s5.lib"): + lib=os.path.join(qtlibs,k%i) + if os.path.exists(lib): + env.append_unique('LIB_'+uselib,i+k[k.find("%s")+2:k.find('.')]) + self.msg('Checking for %s'%i,lib,'GREEN') + break + else: + self.msg('Checking for %s'%i,False,'YELLOW') + env.append_unique('LIBPATH_'+uselib,qtlibs) + env.append_unique('INCLUDES_'+uselib,qtincludes) + env.append_unique('INCLUDES_'+uselib,os.path.join(qtincludes,i)) + uselib=i.upper()+"_debug" + for k in("lib%sd.a","lib%sd5.a","%sd.lib","%sd5.lib"): + lib=os.path.join(qtlibs,k%i) + if os.path.exists(lib): + env.append_unique('LIB_'+uselib,i+k[k.find("%s")+2:k.find('.')]) + self.msg('Checking for %s'%i,lib,'GREEN') + break + else: + self.msg('Checking for %s'%i,False,'YELLOW') + env.append_unique('LIBPATH_'+uselib,qtlibs) + env.append_unique('INCLUDES_'+uselib,qtincludes) + env.append_unique('INCLUDES_'+uselib,os.path.join(qtincludes,i)) + else: + for i in self.qt5_vars_debug+self.qt5_vars: + self.check_cfg(package=i,args='--cflags --libs',mandatory=False) +@conf +def simplify_qt5_libs(self): + env=self.env + def process_lib(vars_,coreval): + for d in vars_: + var=d.upper() + if var=='QTCORE': + continue + value=env['LIBPATH_'+var] + if value: + core=env[coreval] + accu=[] + for lib in value: + if lib in core: + continue + accu.append(lib) + env['LIBPATH_'+var]=accu + process_lib(self.qt5_vars,'LIBPATH_QTCORE') + process_lib(self.qt5_vars_debug,'LIBPATH_QTCORE_DEBUG') +@conf +def add_qt5_rpath(self): + env=self.env + if getattr(Options.options,'want_rpath',False): + def process_rpath(vars_,coreval): + for d in vars_: + var=d.upper() + value=env['LIBPATH_'+var] + if value: + core=env[coreval] + accu=[] + for lib in value: + if var!='QTCORE': + if lib in core: + continue + accu.append('-Wl,--rpath='+lib) + env['RPATH_'+var]=accu + process_rpath(self.qt5_vars,'LIBPATH_QTCORE') + process_rpath(self.qt5_vars_debug,'LIBPATH_QTCORE_DEBUG') +@conf +def set_qt5_libs_to_check(self): + if not hasattr(self,'qt5_vars'): + self.qt5_vars=QT5_LIBS + self.qt5_vars=Utils.to_list(self.qt5_vars) + if not hasattr(self,'qt5_vars_debug'): + self.qt5_vars_debug=[a+'_debug'for a in self.qt5_vars] + self.qt5_vars_debug=Utils.to_list(self.qt5_vars_debug) +@conf +def set_qt5_defines(self): + if sys.platform!='win32': + return + for x in self.qt5_vars: + y=x[2:].upper() + self.env.append_unique('DEFINES_%s'%x.upper(),'QT_%s_LIB'%y) + self.env.append_unique('DEFINES_%s_DEBUG'%x.upper(),'QT_%s_LIB'%y) +def options(opt): + opt.add_option('--want-rpath',action='store_true',default=False,dest='want_rpath',help='enable the rpath for qt libraries') + opt.add_option('--header-ext',type='string',default='',help='header extension for moc files',dest='qt_header_ext') + for i in'qtdir qtbin qtlibs'.split(): + opt.add_option('--'+i,type='string',default='',dest=i) + opt.add_option('--translate',action="store_true",help="collect translation strings",dest="trans_qt5",default=False) diff --git a/waflib/Tools/ruby.py b/waflib/Tools/ruby.py index 04cddfb1..32a36bd2 100644 --- a/waflib/Tools/ruby.py +++ b/waflib/Tools/ruby.py @@ -27,7 +27,7 @@ def check_ruby_version(self,minver=()): self.find_program('ruby',var='RUBY') ruby=self.env.RUBY try: - version=self.cmd_and_log([ruby,'-e','puts defined?(VERSION) ? VERSION : RUBY_VERSION']).strip() + version=self.cmd_and_log(ruby+['-e','puts defined?(VERSION) ? VERSION : RUBY_VERSION']).strip() except Exception: self.fatal('could not determine ruby version') self.env.RUBY_VERSION=version @@ -51,9 +51,9 @@ def check_ruby_ext_devel(self): self.fatal('load a c/c++ compiler first') version=tuple(map(int,self.env.RUBY_VERSION.split("."))) def read_out(cmd): - return Utils.to_list(self.cmd_and_log([self.env.RUBY,'-rrbconfig','-e',cmd])) + return Utils.to_list(self.cmd_and_log(self.env.RUBY+['-rrbconfig','-e',cmd])) def read_config(key): - return read_out('puts Config::CONFIG[%r]'%key) + return read_out('puts RbConfig::CONFIG[%r]'%key) ruby=self.env['RUBY'] archdir=read_config('archdir') cpppath=archdir @@ -87,7 +87,7 @@ def check_ruby_ext_devel(self): def check_ruby_module(self,module_name): self.start_msg('Ruby module %s'%module_name) try: - self.cmd_and_log([self.env['RUBY'],'-e','require \'%s\';puts 1'%module_name]) + self.cmd_and_log(self.env.RUBY+['-e','require \'%s\';puts 1'%module_name]) except Exception: self.end_msg(False) self.fatal('Could not find the ruby module %r'%module_name) diff --git a/waflib/Tools/suncc.py b/waflib/Tools/suncc.py index 48f4943a..6b7bb607 100644 --- a/waflib/Tools/suncc.py +++ b/waflib/Tools/suncc.py @@ -2,25 +2,18 @@ # encoding: utf-8 # WARNING! Do not edit! http://waf.googlecode.com/git/docs/wafbook/single.html#_obtaining_the_waf_file -import os from waflib import Utils from waflib.Tools import ccroot,ar from waflib.Configure import conf @conf def find_scc(conf): v=conf.env - cc=None - if v['CC']:cc=v['CC'] - elif'CC'in conf.environ:cc=conf.environ['CC'] - if not cc:cc=conf.find_program('cc',var='CC') - if not cc:conf.fatal('Could not find a Sun C compiler') - cc=conf.cmd_to_list(cc) + cc=conf.find_program('cc',var='CC') try: conf.cmd_and_log(cc+['-flags']) except Exception: conf.fatal('%r is not a Sun compiler'%cc) - v['CC']=cc - v['CC_NAME']='sun' + v.CC_NAME='sun' conf.get_suncc_version(cc) @conf def scc_common_flags(conf): diff --git a/waflib/Tools/suncxx.py b/waflib/Tools/suncxx.py index 1736c2d1..721180c2 100644 --- a/waflib/Tools/suncxx.py +++ b/waflib/Tools/suncxx.py @@ -2,26 +2,18 @@ # encoding: utf-8 # WARNING! Do not edit! http://waf.googlecode.com/git/docs/wafbook/single.html#_obtaining_the_waf_file -import os from waflib import Utils from waflib.Tools import ccroot,ar from waflib.Configure import conf @conf def find_sxx(conf): v=conf.env - cc=None - if v['CXX']:cc=v['CXX'] - elif'CXX'in conf.environ:cc=conf.environ['CXX'] - if not cc:cc=conf.find_program('CC',var='CXX') - if not cc:cc=conf.find_program('c++',var='CXX') - if not cc:conf.fatal('Could not find a Sun C++ compiler') - cc=conf.cmd_to_list(cc) + cc=conf.find_program(['CC','c++'],var='CXX') try: conf.cmd_and_log(cc+['-flags']) except Exception: conf.fatal('%r is not a Sun compiler'%cc) - v['CXX']=cc - v['CXX_NAME']='sun' + v.CXX_NAME='sun' conf.get_suncc_version(cc) @conf def sxx_common_flags(conf): diff --git a/waflib/Tools/tex.py b/waflib/Tools/tex.py index 68130221..c58c040a 100644 --- a/waflib/Tools/tex.py +++ b/waflib/Tools/tex.py @@ -3,7 +3,7 @@ # WARNING! Do not edit! http://waf.googlecode.com/git/docs/wafbook/single.html#_obtaining_the_waf_file import os,re -from waflib import Utils,Task,Errors,Logs +from waflib import Utils,Task,Errors,Logs,Node from waflib.TaskGen import feature,before_method re_bibunit=re.compile(r'\\(?Pputbib)\[(?P[^\[\]]*)\]',re.M) def bibunitscan(self): @@ -14,7 +14,7 @@ def bibunitscan(self): for match in re_bibunit.finditer(code): path=match.group('file') if path: - for k in['','.bib']: + for k in('','.bib'): Logs.debug('tex: trying %s%s'%(path,k)) fi=node.parent.find_resource(path+k) if fi: @@ -23,10 +23,11 @@ def bibunitscan(self): Logs.debug('tex: could not find %s'%path) Logs.debug("tex: found the following bibunit files: %s"%nodes) return nodes -exts_deps_tex=['','.ltx','.tex','.bib','.pdf','.png','.eps','.ps'] +exts_deps_tex=['','.ltx','.tex','.bib','.pdf','.png','.eps','.ps','.sty'] exts_tex=['.ltx','.tex'] -re_tex=re.compile(r'\\(?Pinclude|bibliography|putbib|includegraphics|input|import|bringin|lstinputlisting)(\[[^\[\]]*\])?{(?P[^{}]*)}',re.M) +re_tex=re.compile(r'\\(?Pusepackage|RequirePackage|include|bibliography([^\[\]{}]*)|putbib|includegraphics|input|import|bringin|lstinputlisting)(\[[^\[\]]*\])?{(?P[^{}]*)}',re.M) g_bibtex_re=re.compile('bibdata',re.M) +g_glossaries_re=re.compile('\\@newglossary',re.M) class tex(Task.Task): bibtex_fun,_=Task.compile_fun('${BIBTEX} ${BIBTEXFLAGS} ${SRCFILE}',shell=False) bibtex_fun.__doc__=""" @@ -36,8 +37,13 @@ class tex(Task.Task): makeindex_fun.__doc__=""" Execute the program **makeindex** """ + makeglossaries_fun,_=Task.compile_fun('${MAKEGLOSSARIES} ${SRCFILE}',shell=False) + makeglossaries_fun.__doc__=""" + Execute the program **makeglossaries** + """ def exec_command(self,cmd,**kw): bld=self.generator.bld + Logs.info('runner: %r'%cmd) try: if not kw.get('cwd',None): kw['cwd']=bld.cwd @@ -71,13 +77,23 @@ class tex(Task.Task): code=node.read() global re_tex for match in re_tex.finditer(code): + multibib=match.group('type') + if multibib and multibib.startswith('bibliography'): + multibib=multibib[len('bibliography'):] + if multibib.startswith('style'): + continue + else: + multibib=None for path in match.group('file').split(','): if path: add_name=True found=None for k in exts_deps_tex: - Logs.debug('tex: trying %s%s'%(path,k)) - found=node.parent.find_resource(path+k) + for up in self.texinputs_nodes: + Logs.debug('tex: trying %s%s'%(path,k)) + found=up.find_resource(path+k) + if found: + break for tsk in self.generator.tasks: if not found or found in tsk.outputs: break @@ -88,6 +104,11 @@ class tex(Task.Task): if found.name.endswith(ext): parse_node(found) break + if found and multibib and found.name.endswith('.bib'): + try: + self.multibibs.append(found) + except AttributeError: + self.multibibs=[found] if add_name: names.append(path) parse_node(node) @@ -102,16 +123,22 @@ class tex(Task.Task): for aux_node in self.aux_nodes: try: ct=aux_node.read() - except(OSError,IOError): + except EnvironmentError: Logs.error('Error reading %s: %r'%aux_node.abspath()) continue if g_bibtex_re.findall(ct): - Logs.warn('calling bibtex') + Logs.info('calling bibtex') self.env.env={} self.env.env.update(os.environ) - self.env.env.update({'BIBINPUTS':self.TEXINPUTS,'BSTINPUTS':self.TEXINPUTS}) + self.env.env.update({'BIBINPUTS':self.texinputs(),'BSTINPUTS':self.texinputs()}) self.env.SRCFILE=aux_node.name[:-4] self.check_status('error when calling bibtex',self.bibtex_fun()) + for node in getattr(self,'multibibs',[]): + self.env.env={} + self.env.env.update(os.environ) + self.env.env.update({'BIBINPUTS':self.texinputs(),'BSTINPUTS':self.texinputs()}) + self.env.SRCFILE=node.name[:-4] + self.check_status('error when calling bibtex',self.bibtex_fun()) def bibunits(self): try: bibunits=bibunitscan(self) @@ -119,21 +146,22 @@ class tex(Task.Task): Logs.error('error bibunitscan') else: if bibunits: - fn=['bu'+str(i)for i in xrange(1,len(bibunits)+1)] + fn=['bu'+str(i)for i in range(1,len(bibunits)+1)] if fn: - Logs.warn('calling bibtex on bibunits') + Logs.info('calling bibtex on bibunits') for f in fn: - self.env.env={'BIBINPUTS':self.TEXINPUTS,'BSTINPUTS':self.TEXINPUTS} + self.env.env={'BIBINPUTS':self.texinputs(),'BSTINPUTS':self.texinputs()} self.env.SRCFILE=f self.check_status('error when calling bibtex',self.bibtex_fun()) def makeindex(self): + self.idx_node=self.inputs[0].change_ext('.idx') try: idx_path=self.idx_node.abspath() os.stat(idx_path) except OSError: - Logs.warn('index file %s absent, not calling makeindex'%idx_path) + Logs.info('index file %s absent, not calling makeindex'%idx_path) else: - Logs.warn('calling makeindex') + Logs.info('calling makeindex') self.env.SRCFILE=self.idx_node.name self.env.env={} self.check_status('error when calling makeindex %s'%idx_path,self.makeindex_fun()) @@ -141,47 +169,65 @@ class tex(Task.Task): p=self.inputs[0].parent.get_bld() if os.path.exists(os.path.join(p.abspath(),'btaux.aux')): self.aux_nodes+=p.ant_glob('*[0-9].aux') + def makeglossaries(self): + src_file=self.inputs[0].abspath() + base_file=os.path.basename(src_file) + base,_=os.path.splitext(base_file) + for aux_node in self.aux_nodes: + try: + ct=aux_node.read() + except EnvironmentError: + Logs.error('Error reading %s: %r'%aux_node.abspath()) + continue + if g_glossaries_re.findall(ct): + if not self.env.MAKEGLOSSARIES: + raise Errors.WafError("The program 'makeglossaries' is missing!") + Logs.warn('calling makeglossaries') + self.env.SRCFILE=base + self.check_status('error when calling makeglossaries %s'%base,self.makeglossaries_fun()) + return + def texinputs(self): + return os.pathsep.join([k.abspath()for k in self.texinputs_nodes])+os.pathsep def run(self): env=self.env if not env['PROMPT_LATEX']: env.append_value('LATEXFLAGS','-interaction=batchmode') env.append_value('PDFLATEXFLAGS','-interaction=batchmode') env.append_value('XELATEXFLAGS','-interaction=batchmode') - fun=self.texfun - node=self.inputs[0] - srcfile=node.abspath() - texinputs=self.env.TEXINPUTS or'' - self.TEXINPUTS=node.parent.get_bld().abspath()+os.pathsep+node.parent.get_src().abspath()+os.pathsep+texinputs+os.pathsep self.cwd=self.inputs[0].parent.get_bld().abspath() - Logs.warn('first pass on %s'%self.__class__.__name__) - self.env.env={} - self.env.env.update(os.environ) - self.env.env.update({'TEXINPUTS':self.TEXINPUTS}) - self.env.SRCFILE=srcfile - self.check_status('error when calling latex',fun()) - self.aux_nodes=self.scan_aux(node.change_ext('.aux')) - self.idx_node=node.change_ext('.idx') + Logs.info('first pass on %s'%self.__class__.__name__) + cur_hash=self.hash_aux_nodes() + self.call_latex() + self.hash_aux_nodes() self.bibtopic() self.bibfile() self.bibunits() self.makeindex() - hash='' + self.makeglossaries() for i in range(10): - prev_hash=hash - try: - hashes=[Utils.h_file(x.abspath())for x in self.aux_nodes] - hash=Utils.h_list(hashes) - except(OSError,IOError): - Logs.error('could not read aux.h') - pass - if hash and hash==prev_hash: + prev_hash=cur_hash + cur_hash=self.hash_aux_nodes() + if not cur_hash: + Logs.error('No aux.h to process') + if cur_hash and cur_hash==prev_hash: break - Logs.warn('calling %s'%self.__class__.__name__) - self.env.env={} - self.env.env.update(os.environ) - self.env.env.update({'TEXINPUTS':self.TEXINPUTS}) - self.env.SRCFILE=srcfile - self.check_status('error when calling %s'%self.__class__.__name__,fun()) + Logs.info('calling %s'%self.__class__.__name__) + self.call_latex() + def hash_aux_nodes(self): + try: + nodes=self.aux_nodes + except AttributeError: + try: + self.aux_nodes=self.scan_aux(self.inputs[0].change_ext('.aux')) + except IOError: + return None + return Utils.h_list([Utils.h_file(x.abspath())for x in self.aux_nodes]) + def call_latex(self): + self.env.env={} + self.env.env.update(os.environ) + self.env.env.update({'TEXINPUTS':self.texinputs()}) + self.env.SRCFILE=self.inputs[0].abspath() + self.check_status('error when calling latex',self.texfun()) class latex(tex): texfun,vars=Task.compile_fun('${LATEX} ${LATEXFLAGS} ${SRCFILE}',shell=False) class pdflatex(tex): @@ -203,7 +249,7 @@ class pdf2ps(Task.Task): @feature('tex') @before_method('process_source') def apply_tex(self): - if not getattr(self,'type',None)in['latex','pdflatex','xelatex']: + if not getattr(self,'type',None)in('latex','pdflatex','xelatex'): self.type='pdflatex' tree=self.bld outs=Utils.to_list(getattr(self,'outs',[])) @@ -211,12 +257,15 @@ def apply_tex(self): deps_lst=[] if getattr(self,'deps',None): deps=self.to_list(self.deps) - for filename in deps: - n=self.path.find_resource(filename) - if not n: - self.bld.fatal('Could not find %r for %r'%(filename,self)) - if not n in deps_lst: - deps_lst.append(n) + for dep in deps: + if isinstance(dep,str): + n=self.path.find_resource(dep) + if not n: + self.bld.fatal('Could not find %r for %r'%(dep,self)) + if not n in deps_lst: + deps_lst.append(n) + elif isinstance(dep,Node.Node): + deps_lst.append(dep) for node in self.to_nodes(self.source): if self.type=='latex': task=self.create_task('latex',node,node.change_ext('.dvi')) @@ -226,30 +275,42 @@ def apply_tex(self): task=self.create_task('xelatex',node,node.change_ext('.pdf')) task.env=self.env if deps_lst: - try: - lst=tree.node_deps[task.uid()] - for n in deps_lst: - if not n in lst: - lst.append(n) - except KeyError: - tree.node_deps[task.uid()]=deps_lst - v=dict(os.environ) - p=node.parent.abspath()+os.pathsep+self.path.abspath()+os.pathsep+self.path.get_bld().abspath()+os.pathsep+v.get('TEXINPUTS','')+os.pathsep - v['TEXINPUTS']=p + for n in deps_lst: + if not n in task.dep_nodes: + task.dep_nodes.append(n) + if hasattr(self,'texinputs_nodes'): + task.texinputs_nodes=self.texinputs_nodes + else: + task.texinputs_nodes=[node.parent,node.parent.get_bld(),self.path,self.path.get_bld()] + lst=os.environ.get('TEXINPUTS','') + if self.env.TEXINPUTS: + lst+=os.pathsep+self.env.TEXINPUTS + if lst: + lst=lst.split(os.pathsep) + for x in lst: + if x: + if os.path.isabs(x): + p=self.bld.root.find_node(x) + if p: + task.texinputs_nodes.append(p) + else: + Logs.error('Invalid TEXINPUTS folder %s'%x) + else: + Logs.error('Cannot resolve relative paths in TEXINPUTS %s'%x) if self.type=='latex': if'ps'in outs: tsk=self.create_task('dvips',task.outputs,node.change_ext('.ps')) - tsk.env.env=dict(v) + tsk.env.env=dict(os.environ) if'pdf'in outs: tsk=self.create_task('dvipdf',task.outputs,node.change_ext('.pdf')) - tsk.env.env=dict(v) + tsk.env.env=dict(os.environ) elif self.type=='pdflatex': if'ps'in outs: self.create_task('pdf2ps',task.outputs,node.change_ext('.ps')) self.source=[] def configure(self): v=self.env - for p in'tex latex pdflatex xelatex bibtex dvips dvipdf ps2pdf makeindex pdf2ps'.split(): + for p in'tex latex pdflatex xelatex bibtex dvips dvipdf ps2pdf makeindex pdf2ps makeglossaries'.split(): try: self.find_program(p,var=p.upper()) except self.errors.ConfigurationError: diff --git a/waflib/Tools/vala.py b/waflib/Tools/vala.py index 96248c1c..e50eb867 100644 --- a/waflib/Tools/vala.py +++ b/waflib/Tools/vala.py @@ -10,7 +10,7 @@ class valac(Task.Task): vars=["VALAC","VALAC_VERSION","VALAFLAGS"] ext_out=['.h'] def run(self): - cmd=[self.env['VALAC']]+self.env['VALAFLAGS'] + cmd=self.env.VALAC+self.env.VALAFLAGS cmd.extend([a.abspath()for a in self.inputs]) ret=self.exec_command(cmd,cwd=self.outputs[0].parent.abspath()) if ret: @@ -159,7 +159,7 @@ def vala_file(self,node): def find_valac(self,valac_name,min_version): valac=self.find_program(valac_name,var='VALAC') try: - output=self.cmd_and_log(valac+' --version') + output=self.cmd_and_log(valac+['--version']) except Exception: valac_version=None else: diff --git a/waflib/Tools/waf_unit_test.py b/waflib/Tools/waf_unit_test.py index 3363172a..5278b202 100644 --- a/waflib/Tools/waf_unit_test.py +++ b/waflib/Tools/waf_unit_test.py @@ -2,8 +2,8 @@ # encoding: utf-8 # WARNING! Do not edit! http://waf.googlecode.com/git/docs/wafbook/single.html#_obtaining_the_waf_file -import os,sys -from waflib.TaskGen import feature,after_method +import os +from waflib.TaskGen import feature,after_method,taskgen_method from waflib import Utils,Task,Logs,Options testlock=Utils.threading.Lock() @feature('test') @@ -11,6 +11,14 @@ testlock=Utils.threading.Lock() def make_test(self): if getattr(self,'link_task',None): self.create_task('utest',self.link_task.outputs) +@taskgen_method +def add_test_results(self,tup): + Logs.debug("ut: %r",tup) + self.utest_result=tup + try: + self.bld.utest_results.append(tup) + except AttributeError: + self.bld.utest_results=[tup] class utest(Task.Task): color='PINK' after=['vnum','inst'] @@ -23,11 +31,9 @@ class utest(Task.Task): if getattr(Options.options,'all_tests',False): return Task.RUN_ME return ret - def run(self): - filename=self.inputs[0].abspath() - self.ut_exec=getattr(self.generator,'ut_exec',[filename]) - if getattr(self.generator,'ut_fun',None): - self.generator.ut_fun(self) + def add_path(self,dct,path,var): + dct[var]=os.pathsep.join(Utils.to_list(path)+[os.environ.get(var,'')]) + def get_test_env(self): try: fu=getattr(self.generator.bld,'all_test_paths') except AttributeError: @@ -39,32 +45,30 @@ class utest(Task.Task): s=tg.link_task.outputs[0].parent.abspath() if s not in lst: lst.append(s) - def add_path(dct,path,var): - dct[var]=os.pathsep.join(Utils.to_list(path)+[os.environ.get(var,'')]) if Utils.is_win32: - add_path(fu,lst,'PATH') + self.add_path(fu,lst,'PATH') elif Utils.unversioned_sys_platform()=='darwin': - add_path(fu,lst,'DYLD_LIBRARY_PATH') - add_path(fu,lst,'LD_LIBRARY_PATH') + self.add_path(fu,lst,'DYLD_LIBRARY_PATH') + self.add_path(fu,lst,'LD_LIBRARY_PATH') else: - add_path(fu,lst,'LD_LIBRARY_PATH') + self.add_path(fu,lst,'LD_LIBRARY_PATH') self.generator.bld.all_test_paths=fu + return fu + def run(self): + filename=self.inputs[0].abspath() + self.ut_exec=getattr(self.generator,'ut_exec',[filename]) + if getattr(self.generator,'ut_fun',None): + self.generator.ut_fun(self) cwd=getattr(self.generator,'ut_cwd','')or self.inputs[0].parent.abspath() - testcmd=getattr(Options.options,'testcmd',False) + testcmd=getattr(self.generator,'ut_cmd',False)or getattr(Options.options,'testcmd',False) if testcmd: self.ut_exec=(testcmd%self.ut_exec[0]).split(' ') - proc=Utils.subprocess.Popen(self.ut_exec,cwd=cwd,env=fu,stderr=Utils.subprocess.PIPE,stdout=Utils.subprocess.PIPE) + proc=Utils.subprocess.Popen(self.ut_exec,cwd=cwd,env=self.get_test_env(),stderr=Utils.subprocess.PIPE,stdout=Utils.subprocess.PIPE) (stdout,stderr)=proc.communicate() tup=(filename,proc.returncode,stdout,stderr) - self.generator.utest_result=tup testlock.acquire() try: - bld=self.generator.bld - Logs.debug("ut: %r",tup) - try: - bld.utest_results.append(tup) - except AttributeError: - bld.utest_results=[tup] + return self.generator.add_test_results(tup) finally: testlock.release() def summary(bld): diff --git a/waflib/Tools/xlc.py b/waflib/Tools/xlc.py index fbf0fcfd..829617de 100644 --- a/waflib/Tools/xlc.py +++ b/waflib/Tools/xlc.py @@ -7,10 +7,8 @@ from waflib.Configure import conf @conf def find_xlc(conf): cc=conf.find_program(['xlc_r','xlc'],var='CC') - cc=conf.cmd_to_list(cc) conf.get_xlc_version(cc) conf.env.CC_NAME='xlc' - conf.env.CC=cc @conf def xlc_common_flags(conf): v=conf.env diff --git a/waflib/Tools/xlcxx.py b/waflib/Tools/xlcxx.py index b7efb239..e1b98b28 100644 --- a/waflib/Tools/xlcxx.py +++ b/waflib/Tools/xlcxx.py @@ -7,10 +7,8 @@ from waflib.Configure import conf @conf def find_xlcxx(conf): cxx=conf.find_program(['xlc++_r','xlc++'],var='CXX') - cxx=conf.cmd_to_list(cxx) conf.get_xlc_version(cxx) conf.env.CXX_NAME='xlc++' - conf.env.CXX=cxx @conf def xlcxx_common_flags(conf): v=conf.env diff --git a/waflib/Utils.py b/waflib/Utils.py index 92cfd818..d1a59f97 100644 --- a/waflib/Utils.py +++ b/waflib/Utils.py @@ -2,14 +2,9 @@ # encoding: utf-8 # WARNING! Do not edit! http://waf.googlecode.com/git/docs/wafbook/single.html#_obtaining_the_waf_file -import os,sys,errno,traceback,inspect,re,shutil,datetime,gc +import os,sys,errno,traceback,inspect,re,shutil,datetime,gc,platform import subprocess -try: - from collections import deque -except ImportError: - class deque(list): - def popleft(self): - return self.pop(0) +from collections import deque,defaultdict try: import _winreg as winreg except ImportError: @@ -32,6 +27,8 @@ except ImportError: try: import threading except ImportError: + if not'JOBS'in os.environ: + os.environ['JOBS']='1' class threading(object): pass class Lock(object): @@ -56,23 +53,34 @@ O755=493 rot_chr=['\\','|','/','-'] rot_idx=0 try: - from collections import defaultdict + from collections import OrderedDict as ordered_iter_dict except ImportError: - class defaultdict(dict): - def __init__(self,default_factory): - super(defaultdict,self).__init__() - self.default_factory=default_factory - def __getitem__(self,key): + class ordered_iter_dict(dict): + def __init__(self,*k,**kw): + self.lst=[] + dict.__init__(self,*k,**kw) + def clear(self): + dict.clear(self) + self.lst=[] + def __setitem__(self,key,value): + dict.__setitem__(self,key,value) + try: + self.lst.remove(key) + except ValueError: + pass + self.lst.append(key) + def __delitem__(self,key): + dict.__delitem__(self,key) try: - return super(defaultdict,self).__getitem__(key) - except KeyError: - value=self.default_factory() - self[key]=value - return value -is_win32=sys.platform in('win32','cli') -indicator='\x1b[K%s%s%s\r' -if is_win32 and'NOCOLOR'in os.environ: - indicator='%s%s%s\r' + self.lst.remove(key) + except ValueError: + pass + def __iter__(self): + for x in self.lst: + yield x + def keys(self): + return self.lst +is_win32=sys.platform in('win32','cli','os2') def readf(fname,m='r',encoding='ISO8859-1'): if sys.hexversion>0x3000000 and not'b'in m: m+='b' @@ -81,7 +89,10 @@ def readf(fname,m='r',encoding='ISO8859-1'): txt=f.read() finally: f.close() - txt=txt.decode(encoding) + if encoding: + txt=txt.decode(encoding) + else: + txt=txt.decode() else: f=open(fname,m) try: @@ -108,67 +119,70 @@ def h_file(fname): finally: f.close() return m.digest() -if hasattr(os,'O_NOINHERIT')and sys.hexversion<0x3040000: - def readf_win32(f,m='r',encoding='ISO8859-1'): - flags=os.O_NOINHERIT|os.O_RDONLY - if'b'in m: - flags|=os.O_BINARY - if'+'in m: - flags|=os.O_RDWR - try: - fd=os.open(f,flags) - except OSError: - raise IOError('Cannot read from %r'%f) - if sys.hexversion>0x3000000 and not'b'in m: - m+='b' - f=os.fdopen(fd,m) - try: - txt=f.read() - finally: - f.close() - txt=txt.decode(encoding) - else: - f=os.fdopen(fd,m) - try: - txt=f.read() - finally: - f.close() - return txt - def writef_win32(f,data,m='w',encoding='ISO8859-1'): - if sys.hexversion>0x3000000 and not'b'in m: - data=data.encode(encoding) - m+='b' - flags=os.O_CREAT|os.O_TRUNC|os.O_WRONLY|os.O_NOINHERIT - if'b'in m: - flags|=os.O_BINARY - if'+'in m: - flags|=os.O_RDWR - try: - fd=os.open(f,flags) - except OSError: - raise IOError('Cannot write to %r'%f) +def readf_win32(f,m='r',encoding='ISO8859-1'): + flags=os.O_NOINHERIT|os.O_RDONLY + if'b'in m: + flags|=os.O_BINARY + if'+'in m: + flags|=os.O_RDWR + try: + fd=os.open(f,flags) + except OSError: + raise IOError('Cannot read from %r'%f) + if sys.hexversion>0x3000000 and not'b'in m: + m+='b' f=os.fdopen(fd,m) try: - f.write(data) + txt=f.read() finally: f.close() - def h_file_win32(fname): - try: - fd=os.open(fname,os.O_BINARY|os.O_RDONLY|os.O_NOINHERIT) - except OSError: - raise IOError('Cannot read from %r'%fname) - f=os.fdopen(fd,'rb') - m=md5() + if encoding: + txt=txt.decode(encoding) + else: + txt=txt.decode() + else: + f=os.fdopen(fd,m) try: - while fname: - fname=f.read(200000) - m.update(fname) + txt=f.read() finally: f.close() - return m.digest() - readf_old=readf - writef_old=writef - h_file_old=h_file + return txt +def writef_win32(f,data,m='w',encoding='ISO8859-1'): + if sys.hexversion>0x3000000 and not'b'in m: + data=data.encode(encoding) + m+='b' + flags=os.O_CREAT|os.O_TRUNC|os.O_WRONLY|os.O_NOINHERIT + if'b'in m: + flags|=os.O_BINARY + if'+'in m: + flags|=os.O_RDWR + try: + fd=os.open(f,flags) + except OSError: + raise IOError('Cannot write to %r'%f) + f=os.fdopen(fd,m) + try: + f.write(data) + finally: + f.close() +def h_file_win32(fname): + try: + fd=os.open(fname,os.O_BINARY|os.O_RDONLY|os.O_NOINHERIT) + except OSError: + raise IOError('Cannot read from %r'%fname) + f=os.fdopen(fd,'rb') + m=md5() + try: + while fname: + fname=f.read(200000) + m.update(fname) + finally: + f.close() + return m.digest() +readf_unix=readf +writef_unix=writef +h_file_unix=h_file +if hasattr(os,'O_NOINHERIT')and sys.hexversion<0x3040000: readf=readf_win32 writef=writef_win32 h_file=h_file_win32 @@ -190,27 +204,27 @@ Return the hexadecimal representation of a string :param s: string to convert :type s: string """ +def listdir_win32(s): + if not s: + try: + import ctypes + except ImportError: + return[x+':\\'for x in list('ABCDEFGHIJKLMNOPQRSTUVWXYZ')] + else: + dlen=4 + maxdrives=26 + buf=ctypes.create_string_buffer(maxdrives*dlen) + ndrives=ctypes.windll.kernel32.GetLogicalDriveStringsA(maxdrives*dlen,ctypes.byref(buf)) + return[str(buf.raw[4*i:4*i+2].decode('ascii'))for i in range(int(ndrives/dlen))] + if len(s)==2 and s[1]==":": + s+=os.sep + if not os.path.isdir(s): + e=OSError('%s is not a directory'%s) + e.errno=errno.ENOENT + raise e + return os.listdir(s) listdir=os.listdir if is_win32: - def listdir_win32(s): - if not s: - try: - import ctypes - except ImportError: - return[x+':\\'for x in list('ABCDEFGHIJKLMNOPQRSTUVWXYZ')] - else: - dlen=4 - maxdrives=26 - buf=ctypes.create_string_buffer(maxdrives*dlen) - ndrives=ctypes.windll.kernel32.GetLogicalDriveStringsA(maxdrives*dlen,ctypes.byref(buf)) - return[str(buf.raw[4*i:4*i+2].decode('ascii'))for i in range(int(ndrives/dlen))] - if len(s)==2 and s[1]==":": - s+=os.sep - if not os.path.isdir(s): - e=OSError('%s is not a directory'%s) - e.errno=errno.ENOENT - raise e - return os.listdir(s) listdir=listdir_win32 def num2ver(ver): if isinstance(ver,str): @@ -231,18 +245,7 @@ def to_list(sth): return sth.split() else: return sth -re_nl=re.compile('\r*\n',re.M) -def str_to_dict(txt): - tbl={} - lines=re_nl.split(txt) - for x in lines: - x=x.strip() - if not x or x.startswith('#')or x.find('=')<0: - continue - tmp=x.split('=') - tbl[tmp[0].strip()]='='.join(tmp[1:]).strip() - return tbl -def split_path(path): +def split_path_unix(path): return path.split('/') def split_path_cygwin(path): if path.startswith('//'): @@ -261,6 +264,8 @@ if sys.platform=='cygwin': split_path=split_path_cygwin elif is_win32: split_path=split_path_win32 +else: + split_path=split_path_unix split_path.__doc__=""" Split a path by / or \\. This function is not like os.path.split @@ -275,12 +280,29 @@ def check_dir(path): except OSError ,e: if not os.path.isdir(path): raise Errors.WafError('Cannot create the folder %r'%path,ex=e) +def check_exe(name,env=None): + if not name: + raise ValueError('Cannot execute an empty string!') + def is_exe(fpath): + return os.path.isfile(fpath)and os.access(fpath,os.X_OK) + fpath,fname=os.path.split(name) + if fpath and is_exe(name): + return os.path.abspath(name) + else: + env=env or os.environ + for path in env["PATH"].split(os.pathsep): + path=path.strip('"') + exe_file=os.path.join(path,name) + if is_exe(exe_file): + return os.path.abspath(exe_file) + return None def def_attrs(cls,**kw): for k,v in kw.items(): if not hasattr(cls,k): setattr(cls,k,v) def quote_define_name(s): - fu=re.compile("[^a-zA-Z0-9]").sub("_",s) + fu=re.sub('[^a-zA-Z0-9]','_',s) + fu=re.sub('_+','_',fu) fu=fu.upper() return fu def h_list(lst): @@ -336,7 +358,8 @@ def unversioned_sys_platform(): else:s=s.lower() if s=='powerpc': return'darwin' - if s=='win32'or s.endswith('os2')and s!='sunos2':return s + if s=='win32'or s=='os2': + return s return re.split('\d+$',s)[0] def nada(*k,**kw): pass @@ -345,10 +368,10 @@ class Timer(object): self.start_time=datetime.datetime.utcnow() def __str__(self): delta=datetime.datetime.utcnow()-self.start_time - days=int(delta.days) - hours=delta.seconds//3600 - minutes=(delta.seconds-hours*3600)//60 - seconds=delta.seconds-hours*3600-minutes*60+float(delta.microseconds)/1000/1000 + days=delta.days + hours,rem=divmod(delta.seconds,3600) + minutes,seconds=divmod(rem,60) + seconds+=delta.microseconds*1e-6 result='' if days: result+='%dd'%days @@ -410,3 +433,11 @@ def get_registry_app_path(key,filename): else: if os.path.isfile(result): return result +def lib64(): + if os.sep=='/': + is_64=platform.architecture()[0]=='64bit' + if os.path.exists('/usr/lib64')and not os.path.exists('/usr/lib32'): + return'64'if is_64 else'' + else: + return''if is_64 else'32' + return'' diff --git a/waflib/ansiterm.py b/waflib/ansiterm.py index def27e43..68cf26f6 100644 --- a/waflib/ansiterm.py +++ b/waflib/ansiterm.py @@ -2,65 +2,83 @@ # encoding: utf-8 # WARNING! Do not edit! http://waf.googlecode.com/git/docs/wafbook/single.html#_obtaining_the_waf_file -import sys,os +import os,re,sys +from waflib.Utils import threading +wlock=threading.Lock() try: - if not(sys.stderr.isatty()and sys.stdout.isatty()): - raise ValueError('not a tty') - from ctypes import Structure,windll,c_short,c_ushort,c_ulong,c_int,byref,POINTER,c_long,c_char + from ctypes import Structure,windll,c_short,c_ushort,c_ulong,c_int,byref,c_wchar,POINTER,c_long +except ImportError: + class AnsiTerm(object): + def __init__(self,stream): + self.stream=stream + try: + self.errors=self.stream.errors + except AttributeError: + pass + self.encoding=self.stream.encoding + def write(self,txt): + try: + wlock.acquire() + self.stream.write(txt) + self.stream.flush() + finally: + wlock.release() + def fileno(self): + return self.stream.fileno() + def flush(self): + self.stream.flush() + def isatty(self): + return self.stream.isatty() +else: class COORD(Structure): _fields_=[("X",c_short),("Y",c_short)] class SMALL_RECT(Structure): _fields_=[("Left",c_short),("Top",c_short),("Right",c_short),("Bottom",c_short)] class CONSOLE_SCREEN_BUFFER_INFO(Structure): - _fields_=[("Size",COORD),("CursorPosition",COORD),("Attributes",c_short),("Window",SMALL_RECT),("MaximumWindowSize",COORD)] + _fields_=[("Size",COORD),("CursorPosition",COORD),("Attributes",c_ushort),("Window",SMALL_RECT),("MaximumWindowSize",COORD)] class CONSOLE_CURSOR_INFO(Structure): _fields_=[('dwSize',c_ulong),('bVisible',c_int)] + try: + _type=unicode + except NameError: + _type=str + to_int=lambda number,default:number and int(number)or default + STD_OUTPUT_HANDLE=-11 + STD_ERROR_HANDLE=-12 windll.kernel32.GetStdHandle.argtypes=[c_ulong] windll.kernel32.GetStdHandle.restype=c_ulong windll.kernel32.GetConsoleScreenBufferInfo.argtypes=[c_ulong,POINTER(CONSOLE_SCREEN_BUFFER_INFO)] windll.kernel32.GetConsoleScreenBufferInfo.restype=c_long windll.kernel32.SetConsoleTextAttribute.argtypes=[c_ulong,c_ushort] windll.kernel32.SetConsoleTextAttribute.restype=c_long - windll.kernel32.FillConsoleOutputCharacterA.argtypes=[c_ulong,c_char,c_ulong,POINTER(COORD),POINTER(c_ulong)] - windll.kernel32.FillConsoleOutputCharacterA.restype=c_long + windll.kernel32.FillConsoleOutputCharacterW.argtypes=[c_ulong,c_wchar,c_ulong,POINTER(COORD),POINTER(c_ulong)] + windll.kernel32.FillConsoleOutputCharacterW.restype=c_long windll.kernel32.FillConsoleOutputAttribute.argtypes=[c_ulong,c_ushort,c_ulong,POINTER(COORD),POINTER(c_ulong)] windll.kernel32.FillConsoleOutputAttribute.restype=c_long windll.kernel32.SetConsoleCursorPosition.argtypes=[c_ulong,POINTER(COORD)] windll.kernel32.SetConsoleCursorPosition.restype=c_long windll.kernel32.SetConsoleCursorInfo.argtypes=[c_ulong,POINTER(CONSOLE_CURSOR_INFO)] windll.kernel32.SetConsoleCursorInfo.restype=c_long - sbinfo=CONSOLE_SCREEN_BUFFER_INFO() - csinfo=CONSOLE_CURSOR_INFO() - hconsole=windll.kernel32.GetStdHandle(-11) - windll.kernel32.GetConsoleScreenBufferInfo(hconsole,byref(sbinfo)) - if sbinfo.Size.X<9 or sbinfo.Size.Y<9:raise ValueError('small console') - windll.kernel32.GetConsoleCursorInfo(hconsole,byref(csinfo)) -except Exception: - pass -else: - import re,threading - is_vista=getattr(sys,"getwindowsversion",None)and sys.getwindowsversion()[0]>=6 - try: - _type=unicode - except NameError: - _type=str - to_int=lambda number,default:number and int(number)or default - wlock=threading.Lock() - STD_OUTPUT_HANDLE=-11 - STD_ERROR_HANDLE=-12 class AnsiTerm(object): - def __init__(self): - self.encoding=sys.stdout.encoding - self.hconsole=windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE) + def __init__(self,s): + self.stream=s + try: + self.errors=s.errors + except AttributeError: + pass + self.encoding=s.encoding self.cursor_history=[] - self.orig_sbinfo=CONSOLE_SCREEN_BUFFER_INFO() - self.orig_csinfo=CONSOLE_CURSOR_INFO() - windll.kernel32.GetConsoleScreenBufferInfo(self.hconsole,byref(self.orig_sbinfo)) - windll.kernel32.GetConsoleCursorInfo(hconsole,byref(self.orig_csinfo)) + handle=(s.fileno()==2)and STD_ERROR_HANDLE or STD_OUTPUT_HANDLE + self.hconsole=windll.kernel32.GetStdHandle(handle) + self._sbinfo=CONSOLE_SCREEN_BUFFER_INFO() + self._csinfo=CONSOLE_CURSOR_INFO() + windll.kernel32.GetConsoleCursorInfo(self.hconsole,byref(self._csinfo)) + self._orig_sbinfo=CONSOLE_SCREEN_BUFFER_INFO() + r=windll.kernel32.GetConsoleScreenBufferInfo(self.hconsole,byref(self._orig_sbinfo)) + self._isatty=r==1 def screen_buffer_info(self): - sbinfo=CONSOLE_SCREEN_BUFFER_INFO() - windll.kernel32.GetConsoleScreenBufferInfo(self.hconsole,byref(sbinfo)) - return sbinfo + windll.kernel32.GetConsoleScreenBufferInfo(self.hconsole,byref(self._sbinfo)) + return self._sbinfo def clear_line(self,param): mode=param and int(param)or 0 sbinfo=self.screen_buffer_info() @@ -74,7 +92,7 @@ else: line_start=sbinfo.CursorPosition line_length=sbinfo.Size.X-sbinfo.CursorPosition.X chars_written=c_ulong() - windll.kernel32.FillConsoleOutputCharacterA(self.hconsole,c_char(' '),line_length,line_start,byref(chars_written)) + windll.kernel32.FillConsoleOutputCharacterW(self.hconsole,c_wchar(' '),line_length,line_start,byref(chars_written)) windll.kernel32.FillConsoleOutputAttribute(self.hconsole,sbinfo.Attributes,line_length,line_start,byref(chars_written)) def clear_screen(self,param): mode=to_int(param,0) @@ -90,7 +108,7 @@ else: clear_start=sbinfo.CursorPosition clear_length=((sbinfo.Size.X-sbinfo.CursorPosition.X)+sbinfo.Size.X*(sbinfo.Size.Y-sbinfo.CursorPosition.Y)) chars_written=c_ulong() - windll.kernel32.FillConsoleOutputCharacterA(self.hconsole,c_char(' '),clear_length,clear_start,byref(chars_written)) + windll.kernel32.FillConsoleOutputCharacterW(self.hconsole,c_wchar(' '),clear_length,clear_start,byref(chars_written)) windll.kernel32.FillConsoleOutputAttribute(self.hconsole,sbinfo.Attributes,clear_length,clear_start,byref(chars_written)) def push_cursor(self,param): sbinfo=self.screen_buffer_info() @@ -133,20 +151,16 @@ else: return((c&1)<<2)|(c&2)|((c&4)>>2) def set_color(self,param): cols=param.split(';') - sbinfo=CONSOLE_SCREEN_BUFFER_INFO() - windll.kernel32.GetConsoleScreenBufferInfo(self.hconsole,byref(sbinfo)) + sbinfo=self.screen_buffer_info() attr=sbinfo.Attributes for c in cols: - if is_vista: - c=int(c) - else: - c=to_int(c,0) + c=to_int(c,0) if 29>4)|((attr&0x07)<<4) windll.kernel32.SetConsoleTextAttribute(self.hconsole,attr) def show_cursor(self,param): - csinfo.bVisible=1 - windll.kernel32.SetConsoleCursorInfo(self.hconsole,byref(csinfo)) + self._csinfo.bVisible=1 + windll.kernel32.SetConsoleCursorInfo(self.hconsole,byref(self._csinfo)) def hide_cursor(self,param): - csinfo.bVisible=0 - windll.kernel32.SetConsoleCursorInfo(self.hconsole,byref(csinfo)) + self._csinfo.bVisible=0 + windll.kernel32.SetConsoleCursorInfo(self.hconsole,byref(self._csinfo)) ansi_command_table={'A':move_up,'B':move_down,'C':move_right,'D':move_left,'E':next_line,'F':prev_line,'G':set_column,'H':set_cursor,'f':set_cursor,'J':clear_screen,'K':clear_line,'h':show_cursor,'l':hide_cursor,'m':set_color,'s':push_cursor,'u':pop_cursor,} ansi_tokens=re.compile('(?:\x1b\[([0-9?;]*)([a-zA-Z])|([^\x1b]+))') def write(self,text): try: wlock.acquire() - for param,cmd,txt in self.ansi_tokens.findall(text): - if cmd: - cmd_func=self.ansi_command_table.get(cmd) - if cmd_func: - cmd_func(self,param) - else: - self.writeconsole(txt) + if self._isatty: + for param,cmd,txt in self.ansi_tokens.findall(text): + if cmd: + cmd_func=self.ansi_command_table.get(cmd) + if cmd_func: + cmd_func(self,param) + else: + self.writeconsole(txt) + else: + self.stream.write(text) finally: wlock.release() def writeconsole(self,txt): @@ -179,13 +196,43 @@ else: writeconsole=windll.kernel32.WriteConsoleA if isinstance(txt,_type): writeconsole=windll.kernel32.WriteConsoleW - TINY_STEP=3000 - for x in range(0,len(txt),TINY_STEP): - tiny=txt[x:x+TINY_STEP] - writeconsole(self.hconsole,tiny,len(tiny),byref(chars_written),None) + done=0 + todo=len(txt) + chunk=32<<10 + while todo!=0: + doing=min(chunk,todo) + buf=txt[done:done+doing] + r=writeconsole(self.hconsole,buf,doing,byref(chars_written),None) + if r==0: + chunk>>=1 + continue + done+=doing + todo-=doing + def fileno(self): + return self.stream.fileno() def flush(self): pass def isatty(self): - return True - sys.stderr=sys.stdout=AnsiTerm() - os.environ['TERM']='vt100' + return self._isatty + if sys.stdout.isatty()or sys.stderr.isatty(): + handle=sys.stdout.isatty()and STD_OUTPUT_HANDLE or STD_ERROR_HANDLE + console=windll.kernel32.GetStdHandle(handle) + sbinfo=CONSOLE_SCREEN_BUFFER_INFO() + def get_term_cols(): + windll.kernel32.GetConsoleScreenBufferInfo(console,byref(sbinfo)) + return sbinfo.Size.X-1 +try: + import struct,fcntl,termios +except ImportError: + pass +else: + if(sys.stdout.isatty()or sys.stderr.isatty())and os.environ.get('TERM','')not in('dumb','emacs'): + FD=sys.stdout.isatty()and sys.stdout.fileno()or sys.stderr.fileno() + def fun(): + return struct.unpack("HHHH",fcntl.ioctl(FD,termios.TIOCGWINSZ,struct.pack("HHHH",0,0,0,0)))[1] + try: + fun() + except Exception ,e: + pass + else: + get_term_cols=fun diff --git a/waflib/extras/compat15.py b/waflib/extras/compat15.py index 3343afc6..8a69dbf0 100644 --- a/waflib/extras/compat15.py +++ b/waflib/extras/compat15.py @@ -26,8 +26,36 @@ Build.BuildContext.add_subdirs=Build.BuildContext.recurse Build.BuildContext.new_task_gen=Build.BuildContext.__call__ Build.BuildContext.is_install=0 Node.Node.relpath_gen=Node.Node.path_from +Utils.pproc=Utils.subprocess +Utils.get_term_cols=Logs.get_term_cols +def cmd_output(cmd,**kw): + silent=False + if'silent'in kw: + silent=kw['silent'] + del(kw['silent']) + if'e'in kw: + tmp=kw['e'] + del(kw['e']) + kw['env']=tmp + kw['shell']=isinstance(cmd,str) + kw['stdout']=Utils.subprocess.PIPE + if silent: + kw['stderr']=Utils.subprocess.PIPE + try: + p=Utils.subprocess.Popen(cmd,**kw) + output=p.communicate()[0] + except OSError ,e: + raise ValueError(str(e)) + if p.returncode: + if not silent: + msg="command execution failed: %s -> %r"%(cmd,str(output)) + raise ValueError(msg) + output='' + return output +Utils.cmd_output=cmd_output def name_to_obj(self,s,env=None): - Logs.warn('compat: change "name_to_obj(name, env)" by "get_tgen_by_name(name)"') + if Logs.verbose: + Logs.warn('compat: change "name_to_obj(name, env)" by "get_tgen_by_name(name)"') return self.get_tgen_by_name(s) Build.BuildContext.name_to_obj=name_to_obj def env_of_name(self,name): @@ -49,13 +77,15 @@ def retrieve(self,name,fromenv=None): self.prepare_env(env) self.all_envs[name]=env else: - if fromenv:Logs.warn("The environment %s may have been configured already"%name) + if fromenv: + Logs.warn("The environment %s may have been configured already"%name) return env Configure.ConfigurationContext.retrieve=retrieve Configure.ConfigurationContext.sub_config=Configure.ConfigurationContext.recurse Configure.ConfigurationContext.check_tool=Configure.ConfigurationContext.load Configure.conftest=Configure.conf Configure.ConfigurationError=Errors.ConfigurationError +Utils.WafError=Errors.WafError Options.OptionsContext.sub_options=Options.OptionsContext.recurse Options.OptionsContext.tool_options=Context.Context.load Options.Handler=Options.OptionsContext @@ -76,24 +106,32 @@ eld=Context.load_tool def load_tool(*k,**kw): ret=eld(*k,**kw) if'set_options'in ret.__dict__: - Logs.warn('compat: rename "set_options" to options') + if Logs.verbose: + Logs.warn('compat: rename "set_options" to options') ret.options=ret.set_options if'detect'in ret.__dict__: - Logs.warn('compat: rename "detect" to "configure"') + if Logs.verbose: + Logs.warn('compat: rename "detect" to "configure"') ret.configure=ret.detect return ret Context.load_tool=load_tool +def get_curdir(self): + return self.path.abspath() +Context.Context.curdir=property(get_curdir,Utils.nada) rev=Context.load_module -def load_module(path): - ret=rev(path) +def load_module(path,encoding=None): + ret=rev(path,encoding) if'set_options'in ret.__dict__: - Logs.warn('compat: rename "set_options" to "options" (%r)'%path) + if Logs.verbose: + Logs.warn('compat: rename "set_options" to "options" (%r)'%path) ret.options=ret.set_options if'srcdir'in ret.__dict__: - Logs.warn('compat: rename "srcdir" to "top" (%r)'%path) + if Logs.verbose: + Logs.warn('compat: rename "srcdir" to "top" (%r)'%path) ret.top=ret.srcdir if'blddir'in ret.__dict__: - Logs.warn('compat: rename "blddir" to "out" (%r)'%path) + if Logs.verbose: + Logs.warn('compat: rename "blddir" to "out" (%r)'%path) ret.out=ret.blddir return ret Context.load_module=load_module @@ -101,15 +139,18 @@ old_post=TaskGen.task_gen.post def post(self): self.features=self.to_list(self.features) if'cc'in self.features: - Logs.warn('compat: the feature cc does not exist anymore (use "c")') + if Logs.verbose: + Logs.warn('compat: the feature cc does not exist anymore (use "c")') self.features.remove('cc') self.features.append('c') if'cstaticlib'in self.features: - Logs.warn('compat: the feature cstaticlib does not exist anymore (use "cstlib" or "cxxstlib")') + if Logs.verbose: + Logs.warn('compat: the feature cstaticlib does not exist anymore (use "cstlib" or "cxxstlib")') self.features.remove('cstaticlib') self.features.append(('cxx'in self.features)and'cxxstlib'or'cstlib') if getattr(self,'ccflags',None): - Logs.warn('compat: "ccflags" was renamed to "cflags"') + if Logs.verbose: + Logs.warn('compat: "ccflags" was renamed to "cflags"') self.cflags=self.ccflags return old_post(self) TaskGen.task_gen.post=post @@ -128,9 +169,11 @@ def apply_uselib_local(self): names=self.to_list(getattr(self,'uselib_local',[])) get=self.bld.get_tgen_by_name seen=set([]) + seen_uselib=set([]) tmp=Utils.deque(names) if tmp: - Logs.warn('compat: "uselib_local" is deprecated, replace by "use"') + if Logs.verbose: + Logs.warn('compat: "uselib_local" is deprecated, replace by "use"') while tmp: lib_name=tmp.popleft() if lib_name in seen: @@ -157,9 +200,11 @@ def apply_uselib_local(self): if not tmp_path in env['LIBPATH']: env.prepend_value('LIBPATH',[tmp_path]) for v in self.to_list(getattr(y,'uselib',[])): - if not env['STLIB_'+v]: - if not v in self.uselib: - self.uselib.insert(0,v) + if v not in seen_uselib: + seen_uselib.add(v) + if not env['STLIB_'+v]: + if not v in self.uselib: + self.uselib.insert(0,v) if getattr(y,'export_includes',None): self.includes.extend(y.to_incnodes(y.export_includes)) @TaskGen.feature('cprogram','cxxprogram','cstlib','cxxstlib','cshlib','cxxshlib','dprogram','dstlib','dshlib') @@ -218,3 +263,17 @@ def set_incdirs(self,val): Logs.warn('compat: change "export_incdirs" by "export_includes"') self.export_includes=val TaskGen.task_gen.export_incdirs=property(None,set_incdirs) +def install_dir(self,path): + if not path: + return[] + destpath=Utils.subst_vars(path,self.env) + if self.is_install>0: + Logs.info('* creating %s'%destpath) + Utils.check_dir(destpath) + elif self.is_install<0: + Logs.info('* removing %s'%destpath) + try: + os.remove(destpath) + except OSError: + pass +Build.BuildContext.install_dir=install_dir