aboutsummaryrefslogtreecommitdiff
path: root/waflib/Tools/python.py
diff options
context:
space:
mode:
Diffstat (limited to 'waflib/Tools/python.py')
-rw-r--r--waflib/Tools/python.py336
1 files changed, 336 insertions, 0 deletions
diff --git a/waflib/Tools/python.py b/waflib/Tools/python.py
new file mode 100644
index 0000000..cdaff84
--- /dev/null
+++ b/waflib/Tools/python.py
@@ -0,0 +1,336 @@
+#! /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 import Utils,Options,Errors
+from waflib.Logs import debug,warn,info,error
+from waflib.TaskGen import extension,before_method,after_method,feature
+from waflib.Configure import conf
+FRAG='''
+#include <Python.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void Py_Initialize(void);
+ void Py_Finalize(void);
+#ifdef __cplusplus
+}
+#endif
+int main()
+{
+ Py_Initialize();
+ Py_Finalize();
+ return 0;
+}
+'''
+INST='''
+import sys, py_compile
+py_compile.compile(sys.argv[1], sys.argv[2], sys.argv[3])
+'''
+DISTUTILS_IMP=['from distutils.sysconfig import get_config_var, get_python_lib']
+def process_py(self,node):
+ try:
+ if not self.bld.is_install:
+ return
+ except:
+ 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:
+ 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:
+ 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]
+ 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))
+def feature_py(self):
+ pass
+def init_pyext(self):
+ try:
+ if not self.install_path:
+ return
+ except AttributeError:
+ self.install_path='${PYTHONARCHDIR}'
+ self.uselib=self.to_list(getattr(self,'uselib',[]))
+ if not'PYEXT'in self.uselib:
+ self.uselib.append('PYEXT')
+ self.env['cshlib_PATTERN']=self.env['cxxshlib_PATTERN']=self.env['macbundle_PATTERN']=self.env['pyext_PATTERN']
+def set_bundle(self):
+ if Utils.unversioned_sys_platform()=='darwin':
+ self.mac_bundle=True
+def init_pyembed(self):
+ self.uselib=self.to_list(getattr(self,'uselib',[]))
+ if not'PYEMBED'in self.uselib:
+ self.uselib.append('PYEMBED')
+def get_python_variables(self,variables,imports=None):
+ if not imports:
+ try:
+ imports=self.python_imports
+ except AttributeError:
+ imports=DISTUTILS_IMP
+ program=list(imports)
+ program.append('')
+ for v in variables:
+ program.append("print(repr(%s))"%v)
+ os_env=dict(os.environ)
+ try:
+ del os_env['MACOSX_DEPLOYMENT_TARGET']
+ except KeyError:
+ pass
+ try:
+ out=self.cmd_and_log(self.env.PYTHON+['-c','\n'.join(program)],env=os_env)
+ except Errors.WafError:
+ self.fatal('The distutils module is unusable: install "python-devel"?')
+ return_values=[]
+ for s in out.split('\n'):
+ s=s.strip()
+ if not s:
+ continue
+ if s=='None':
+ return_values.append(None)
+ elif s[0]=="'"and s[-1]=="'":
+ return_values.append(s[1:-1])
+ elif s[0].isdigit():
+ return_values.append(int(s))
+ else:break
+ return return_values
+def check_python_headers(conf):
+ if not conf.env['CC_NAME']and not conf.env['CXX_NAME']:
+ conf.fatal('load a compiler first (gcc, g++, ..)')
+ if not conf.env['PYTHON_VERSION']:
+ conf.check_python_version()
+ env=conf.env
+ pybin=conf.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()
+ 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)))
+ dct=dict(zip(v,lst))
+ x='MACOSX_DEPLOYMENT_TARGET'
+ if dct[x]:
+ conf.env[x]=conf.environ[x]=dct[x]
+ env['pyext_PATTERN']='%s'+dct['SO']
+ 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'].replace('.','')):
+ if not result and env['LIBPATH_PYEMBED']:
+ path=env['LIBPATH_PYEMBED']
+ conf.to_log("\n\n# Trying default LIBPATH_PYEMBED: %r\n"%path)
+ result=conf.check(lib=name,uselib='PYEMBED',libpath=path,mandatory=False,msg='Checking for library %s in LIBPATH_PYEMBED'%name)
+ if not result and dct['LIBDIR']:
+ path=[dct['LIBDIR']]
+ conf.to_log("\n\n# try again with -L$python_LIBDIR: %r\n"%path)
+ result=conf.check(lib=name,uselib='PYEMBED',libpath=path,mandatory=False,msg='Checking for library %s in LIBDIR'%name)
+ if not result and dct['LIBPL']:
+ path=[dct['LIBPL']]
+ conf.to_log("\n\n# try again with -L$python_LIBPL (some systems don't install the python library in $prefix/lib)\n")
+ result=conf.check(lib=name,uselib='PYEMBED',libpath=path,mandatory=False,msg='Checking for library %s in python_LIBPL'%name)
+ if not result:
+ path=[os.path.join(dct['prefix'],"libs")]
+ conf.to_log("\n\n# try again with -L$prefix/libs, and pythonXY name rather than pythonX.Y (win32)\n")
+ result=conf.check(lib=name,uselib='PYEMBED',libpath=path,mandatory=False,msg='Checking for library %s in $prefix/libs'%name)
+ if result:
+ break
+ if result:
+ env['LIBPATH_PYEMBED']=path
+ 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']):
+ env['LIBPATH_PYEXT']=env['LIBPATH_PYEMBED']
+ env['LIB_PYEXT']=env['LIB_PYEMBED']
+ num='.'.join(env['PYTHON_VERSION'].split('.')[:2])
+ conf.find_program(['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']]
+ if env['CC_NAME']=='gcc':
+ env.append_value('CFLAGS_PYEMBED',['-fno-strict-aliasing'])
+ env.append_value('CFLAGS_PYEXT',['-fno-strict-aliasing'])
+ if env['CXX_NAME']=='gcc':
+ env.append_value('CXXFLAGS_PYEMBED',['-fno-strict-aliasing'])
+ env.append_value('CXXFLAGS_PYEXT',['-fno-strict-aliasing'])
+ if env.CC_NAME=="msvc":
+ from distutils.msvccompiler import MSVCCompiler
+ dist_compiler=MSVCCompiler()
+ dist_compiler.initialize()
+ 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='Could not find the python development headers')
+ except conf.errors.ConfigurationError:
+ conf.check_cfg(path=conf.env.PYTHON_CONFIG,package='',uselib_store='PYEMBED',args=['--cflags','--libs'])
+ conf.check(header_name='Python.h',define_name='HAVE_PYTHON_H',msg='Getting the python flags from python-config',uselib='PYEMBED',fragment=FRAG,errmsg='Could not find the python development headers elsewhere')
+def check_python_version(conf,minver=None):
+ assert minver is None or isinstance(minver,tuple)
+ pybin=conf.env['PYTHON']
+ if not pybin:
+ conf.fatal('could not find the python executable')
+ cmd=pybin+['-c','import sys\nfor x in sys.version_info: print(str(x))']
+ debug('python: Running python command %r'%cmd)
+ lines=conf.cmd_and_log(cmd).split()
+ assert len(lines)==5,"found %i lines, expected 5: %r"%(len(lines),lines)
+ pyver_tuple=(int(lines[0]),int(lines[1]),int(lines[2]),lines[3],int(lines[4]))
+ result=(minver is None)or(pyver_tuple>=minver)
+ if result:
+ pyver='.'.join([str(x)for x in pyver_tuple[:2]])
+ conf.env['PYTHON_VERSION']=pyver
+ if'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']])
+ else:
+ python_LIBDEST=None
+ (pydir,)=conf.get_python_variables(["get_python_lib(standard_lib=0, prefix=%r) or ''"%conf.env['PREFIX']])
+ 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:
+ 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']])
+ if not pyarchdir:
+ pyarchdir=pydir
+ if hasattr(conf,'define'):
+ conf.define('PYTHONDIR',pydir)
+ conf.define('PYTHONARCHDIR',pyarchdir)
+ conf.env['PYTHONDIR']=pydir
+ conf.env['PYTHONARCHDIR']=pyarchdir
+ pyver_full='.'.join(map(str,pyver_tuple[:3]))
+ if minver is None:
+ conf.msg('Checking for python version',pyver_full)
+ else:
+ minver_str='.'.join(map(str,minver))
+ conf.msg('Checking for python version',pyver_tuple,">= %s"%(minver_str,)and'GREEN'or'YELLOW')
+ if not result:
+ conf.fatal('The python version is too old, expecting %r'%(minver,))
+PYTHON_MODULE_TEMPLATE='''
+import %s as current_module
+version = getattr(current_module, '__version__', None)
+if version is not None:
+ print(str(version))
+else:
+ print('unknown version')
+'''
+def check_python_module(conf,module_name,condition=''):
+ msg='Python module %s'%module_name
+ if condition:
+ msg='%s (%s)'%(msg,condition)
+ conf.start_msg(msg)
+ try:
+ ret=conf.cmd_and_log(conf.env['PYTHON']+['-c',PYTHON_MODULE_TEMPLATE%module_name])
+ except Exception:
+ conf.end_msg(False)
+ conf.fatal('Could not find the python module %r'%module_name)
+ ret=ret.strip()
+ if condition:
+ conf.end_msg(ret)
+ if ret=='unknown version':
+ conf.fatal('Could not check the %s version'%module_name)
+ from distutils.version import LooseVersion
+ def num(*k):
+ if isinstance(k[0],int):
+ return LooseVersion('.'.join([str(x)for x in k]))
+ else:
+ return LooseVersion(k[0])
+ d={'num':num,'ver':LooseVersion(ret)}
+ ev=eval(condition,{},d)
+ if not ev:
+ conf.fatal('The %s version does not satisfy the requirements'%module_name)
+ else:
+ if ret=='unknown version':
+ conf.end_msg(True)
+ else:
+ conf.end_msg(ret)
+def configure(conf):
+ try:
+ conf.find_program('python',var='PYTHON')
+ except conf.errors.ConfigurationError:
+ 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:
+ warn("python executable '%s' different from sys.executable '%s'"%(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['PYFLAGS']=''
+ v['PYFLAGS_OPT']='-O'
+ v['PYC']=getattr(Options.options,'pyc',1)
+ v['PYO']=getattr(Options.options,'pyo',1)
+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')
+
+extension('.py')(process_py)
+feature('py')(feature_py)
+feature('pyext')(init_pyext)
+before_method('propagate_uselib_vars','apply_link')(init_pyext)
+after_method('apply_bundle')(init_pyext)
+feature('pyext')(set_bundle)
+before_method('apply_link','apply_bundle')(set_bundle)
+before_method('propagate_uselib_vars')(init_pyembed)
+feature('pyembed')(init_pyembed)
+conf(get_python_variables)
+conf(check_python_headers)
+conf(check_python_version)
+conf(check_python_module) \ No newline at end of file