[0fa325b] | 1 | #! /usr/bin/env python |
---|
| 2 | # encoding: utf-8 |
---|
| 3 | # WARNING! Do not edit! http://waf.googlecode.com/git/docs/wafbook/single.html#_obtaining_the_waf_file |
---|
| 4 | |
---|
| 5 | import os,sys |
---|
| 6 | from waflib import Utils,Options,Errors,Logs |
---|
| 7 | from waflib.TaskGen import extension,before_method,after_method,feature |
---|
| 8 | from waflib.Configure import conf |
---|
| 9 | FRAG=''' |
---|
| 10 | #include <Python.h> |
---|
| 11 | #ifdef __cplusplus |
---|
| 12 | extern "C" { |
---|
| 13 | #endif |
---|
| 14 | void Py_Initialize(void); |
---|
| 15 | void Py_Finalize(void); |
---|
| 16 | #ifdef __cplusplus |
---|
| 17 | } |
---|
| 18 | #endif |
---|
| 19 | int main(int argc, char **argv) |
---|
| 20 | { |
---|
| 21 | (void)argc; (void)argv; |
---|
| 22 | Py_Initialize(); |
---|
| 23 | Py_Finalize(); |
---|
| 24 | return 0; |
---|
| 25 | } |
---|
| 26 | ''' |
---|
| 27 | INST=''' |
---|
| 28 | import sys, py_compile |
---|
| 29 | py_compile.compile(sys.argv[1], sys.argv[2], sys.argv[3]) |
---|
| 30 | ''' |
---|
| 31 | DISTUTILS_IMP=['from distutils.sysconfig import get_config_var, get_python_lib'] |
---|
| 32 | @extension('.py') |
---|
| 33 | def process_py(self,node): |
---|
| 34 | try: |
---|
| 35 | if not self.bld.is_install: |
---|
| 36 | return |
---|
| 37 | except AttributeError: |
---|
| 38 | return |
---|
| 39 | try: |
---|
| 40 | if not self.install_path: |
---|
| 41 | return |
---|
| 42 | except AttributeError: |
---|
| 43 | self.install_path='${PYTHONDIR}' |
---|
| 44 | def inst_py(ctx): |
---|
| 45 | install_from=getattr(self,'install_from',None) |
---|
| 46 | if install_from: |
---|
| 47 | install_from=self.path.find_dir(install_from) |
---|
| 48 | install_pyfile(self,node,install_from) |
---|
| 49 | self.bld.add_post_fun(inst_py) |
---|
| 50 | def install_pyfile(self,node,install_from=None): |
---|
| 51 | from_node=install_from or node.parent |
---|
| 52 | tsk=self.bld.install_as(self.install_path+'/'+node.path_from(from_node),node,postpone=False) |
---|
| 53 | path=tsk.get_install_path() |
---|
| 54 | if self.bld.is_install<0: |
---|
| 55 | Logs.info("+ removing byte compiled python files") |
---|
| 56 | for x in'co': |
---|
| 57 | try: |
---|
| 58 | os.remove(path+x) |
---|
| 59 | except OSError: |
---|
| 60 | pass |
---|
| 61 | if self.bld.is_install>0: |
---|
| 62 | try: |
---|
| 63 | st1=os.stat(path) |
---|
| 64 | except OSError: |
---|
| 65 | Logs.error('The python file is missing, this should not happen') |
---|
| 66 | for x in['c','o']: |
---|
| 67 | do_inst=self.env['PY'+x.upper()] |
---|
| 68 | try: |
---|
| 69 | st2=os.stat(path+x) |
---|
| 70 | except OSError: |
---|
| 71 | pass |
---|
| 72 | else: |
---|
| 73 | if st1.st_mtime<=st2.st_mtime: |
---|
| 74 | do_inst=False |
---|
| 75 | if do_inst: |
---|
| 76 | lst=(x=='o')and[self.env['PYFLAGS_OPT']]or[] |
---|
| 77 | (a,b,c)=(path,path+x,tsk.get_install_path(destdir=False)+x) |
---|
| 78 | argv=self.env['PYTHON']+lst+['-c',INST,a,b,c] |
---|
| 79 | Logs.info('+ byte compiling %r'%(path+x)) |
---|
| 80 | env=self.env.env or None |
---|
| 81 | ret=Utils.subprocess.Popen(argv,env=env).wait() |
---|
| 82 | if ret: |
---|
| 83 | raise Errors.WafError('py%s compilation failed %r'%(x,path)) |
---|
| 84 | @feature('py') |
---|
| 85 | def feature_py(self): |
---|
| 86 | pass |
---|
| 87 | @feature('pyext') |
---|
| 88 | @before_method('propagate_uselib_vars','apply_link') |
---|
| 89 | @after_method('apply_bundle') |
---|
| 90 | def init_pyext(self): |
---|
| 91 | self.uselib=self.to_list(getattr(self,'uselib',[])) |
---|
| 92 | if not'PYEXT'in self.uselib: |
---|
| 93 | self.uselib.append('PYEXT') |
---|
| 94 | self.env.cshlib_PATTERN=self.env.cxxshlib_PATTERN=self.env.macbundle_PATTERN=self.env.pyext_PATTERN |
---|
| 95 | self.env.fcshlib_PATTERN=self.env.dshlib_PATTERN=self.env.pyext_PATTERN |
---|
| 96 | try: |
---|
| 97 | if not self.install_path: |
---|
| 98 | return |
---|
| 99 | except AttributeError: |
---|
| 100 | self.install_path='${PYTHONARCHDIR}' |
---|
| 101 | @feature('pyext') |
---|
| 102 | @before_method('apply_link','apply_bundle') |
---|
| 103 | def set_bundle(self): |
---|
| 104 | if Utils.unversioned_sys_platform()=='darwin': |
---|
| 105 | self.mac_bundle=True |
---|
| 106 | @before_method('propagate_uselib_vars') |
---|
| 107 | @feature('pyembed') |
---|
| 108 | def init_pyembed(self): |
---|
| 109 | self.uselib=self.to_list(getattr(self,'uselib',[])) |
---|
| 110 | if not'PYEMBED'in self.uselib: |
---|
| 111 | self.uselib.append('PYEMBED') |
---|
| 112 | @conf |
---|
| 113 | def get_python_variables(self,variables,imports=None): |
---|
| 114 | if not imports: |
---|
| 115 | try: |
---|
| 116 | imports=self.python_imports |
---|
| 117 | except AttributeError: |
---|
| 118 | imports=DISTUTILS_IMP |
---|
| 119 | program=list(imports) |
---|
| 120 | program.append('') |
---|
| 121 | for v in variables: |
---|
| 122 | program.append("print(repr(%s))"%v) |
---|
| 123 | os_env=dict(os.environ) |
---|
| 124 | try: |
---|
| 125 | del os_env['MACOSX_DEPLOYMENT_TARGET'] |
---|
| 126 | except KeyError: |
---|
| 127 | pass |
---|
| 128 | try: |
---|
| 129 | out=self.cmd_and_log(self.env.PYTHON+['-c','\n'.join(program)],env=os_env) |
---|
| 130 | except Errors.WafError: |
---|
| 131 | self.fatal('The distutils module is unusable: install "python-devel"?') |
---|
| 132 | self.to_log(out) |
---|
| 133 | return_values=[] |
---|
| 134 | for s in out.split('\n'): |
---|
| 135 | s=s.strip() |
---|
| 136 | if not s: |
---|
| 137 | continue |
---|
| 138 | if s=='None': |
---|
| 139 | return_values.append(None) |
---|
| 140 | elif(s[0]=="'"and s[-1]=="'")or(s[0]=='"'and s[-1]=='"'): |
---|
| 141 | return_values.append(eval(s)) |
---|
| 142 | elif s[0].isdigit(): |
---|
| 143 | return_values.append(int(s)) |
---|
| 144 | else:break |
---|
| 145 | return return_values |
---|
| 146 | @conf |
---|
| 147 | def check_python_headers(conf): |
---|
| 148 | env=conf.env |
---|
| 149 | if not env['CC_NAME']and not env['CXX_NAME']: |
---|
| 150 | conf.fatal('load a compiler first (gcc, g++, ..)') |
---|
| 151 | if not env['PYTHON_VERSION']: |
---|
| 152 | conf.check_python_version() |
---|
| 153 | pybin=conf.env.PYTHON |
---|
| 154 | if not pybin: |
---|
| 155 | conf.fatal('Could not find the python executable') |
---|
| 156 | v='prefix SO LDFLAGS LIBDIR LIBPL INCLUDEPY Py_ENABLE_SHARED MACOSX_DEPLOYMENT_TARGET LDSHARED CFLAGS'.split() |
---|
| 157 | try: |
---|
| 158 | lst=conf.get_python_variables(["get_config_var('%s') or ''"%x for x in v]) |
---|
| 159 | except RuntimeError: |
---|
| 160 | conf.fatal("Python development headers not found (-v for details).") |
---|
| 161 | vals=['%s = %r'%(x,y)for(x,y)in zip(v,lst)] |
---|
| 162 | conf.to_log("Configuration returned from %r:\n%r\n"%(pybin,'\n'.join(vals))) |
---|
| 163 | dct=dict(zip(v,lst)) |
---|
| 164 | x='MACOSX_DEPLOYMENT_TARGET' |
---|
| 165 | if dct[x]: |
---|
| 166 | conf.env[x]=conf.environ[x]=dct[x] |
---|
| 167 | env['pyext_PATTERN']='%s'+dct['SO'] |
---|
| 168 | all_flags=dct['LDFLAGS']+' '+dct['CFLAGS'] |
---|
| 169 | conf.parse_flags(all_flags,'PYEMBED') |
---|
| 170 | all_flags=dct['LDFLAGS']+' '+dct['LDSHARED']+' '+dct['CFLAGS'] |
---|
| 171 | conf.parse_flags(all_flags,'PYEXT') |
---|
| 172 | result=None |
---|
[c101fe1] | 173 | for name in('python'+env['PYTHON_VERSION'],'python'+env['PYTHON_VERSION']+'m','python'+env['PYTHON_VERSION'].replace('.','')): |
---|
[0fa325b] | 174 | if not result and env['LIBPATH_PYEMBED']: |
---|
| 175 | path=env['LIBPATH_PYEMBED'] |
---|
| 176 | conf.to_log("\n\n# Trying default LIBPATH_PYEMBED: %r\n"%path) |
---|
| 177 | result=conf.check(lib=name,uselib='PYEMBED',libpath=path,mandatory=False,msg='Checking for library %s in LIBPATH_PYEMBED'%name) |
---|
| 178 | if not result and dct['LIBDIR']: |
---|
| 179 | path=[dct['LIBDIR']] |
---|
| 180 | conf.to_log("\n\n# try again with -L$python_LIBDIR: %r\n"%path) |
---|
| 181 | result=conf.check(lib=name,uselib='PYEMBED',libpath=path,mandatory=False,msg='Checking for library %s in LIBDIR'%name) |
---|
| 182 | if not result and dct['LIBPL']: |
---|
| 183 | path=[dct['LIBPL']] |
---|
| 184 | conf.to_log("\n\n# try again with -L$python_LIBPL (some systems don't install the python library in $prefix/lib)\n") |
---|
| 185 | result=conf.check(lib=name,uselib='PYEMBED',libpath=path,mandatory=False,msg='Checking for library %s in python_LIBPL'%name) |
---|
| 186 | if not result: |
---|
| 187 | path=[os.path.join(dct['prefix'],"libs")] |
---|
| 188 | conf.to_log("\n\n# try again with -L$prefix/libs, and pythonXY name rather than pythonX.Y (win32)\n") |
---|
| 189 | result=conf.check(lib=name,uselib='PYEMBED',libpath=path,mandatory=False,msg='Checking for library %s in $prefix/libs'%name) |
---|
| 190 | if result: |
---|
| 191 | break |
---|
| 192 | if result: |
---|
| 193 | env['LIBPATH_PYEMBED']=path |
---|
| 194 | env.append_value('LIB_PYEMBED',[name]) |
---|
| 195 | else: |
---|
| 196 | conf.to_log("\n\n### LIB NOT FOUND\n") |
---|
| 197 | if(Utils.is_win32 or sys.platform.startswith('os2')or dct['Py_ENABLE_SHARED']): |
---|
| 198 | env['LIBPATH_PYEXT']=env['LIBPATH_PYEMBED'] |
---|
| 199 | env['LIB_PYEXT']=env['LIB_PYEMBED'] |
---|
| 200 | num='.'.join(env['PYTHON_VERSION'].split('.')[:2]) |
---|
| 201 | conf.find_program([''.join(pybin)+'-config','python%s-config'%num,'python-config-%s'%num,'python%sm-config'%num],var='PYTHON_CONFIG',mandatory=False) |
---|
| 202 | includes=[] |
---|
| 203 | if conf.env.PYTHON_CONFIG: |
---|
| 204 | for incstr in conf.cmd_and_log([conf.env.PYTHON_CONFIG,'--includes']).strip().split(): |
---|
| 205 | if(incstr.startswith('-I')or incstr.startswith('/I')): |
---|
| 206 | incstr=incstr[2:] |
---|
| 207 | if incstr not in includes: |
---|
| 208 | includes.append(incstr) |
---|
| 209 | conf.to_log("Include path for Python extensions (found via python-config --includes): %r\n"%(includes,)) |
---|
| 210 | env['INCLUDES_PYEXT']=includes |
---|
| 211 | env['INCLUDES_PYEMBED']=includes |
---|
| 212 | else: |
---|
| 213 | conf.to_log("Include path for Python extensions ""(found via distutils module): %r\n"%(dct['INCLUDEPY'],)) |
---|
| 214 | env['INCLUDES_PYEXT']=[dct['INCLUDEPY']] |
---|
| 215 | env['INCLUDES_PYEMBED']=[dct['INCLUDEPY']] |
---|
| 216 | if env['CC_NAME']=='gcc': |
---|
| 217 | env.append_value('CFLAGS_PYEMBED',['-fno-strict-aliasing']) |
---|
| 218 | env.append_value('CFLAGS_PYEXT',['-fno-strict-aliasing']) |
---|
| 219 | if env['CXX_NAME']=='gcc': |
---|
| 220 | env.append_value('CXXFLAGS_PYEMBED',['-fno-strict-aliasing']) |
---|
| 221 | env.append_value('CXXFLAGS_PYEXT',['-fno-strict-aliasing']) |
---|
| 222 | if env.CC_NAME=="msvc": |
---|
| 223 | from distutils.msvccompiler import MSVCCompiler |
---|
| 224 | dist_compiler=MSVCCompiler() |
---|
| 225 | dist_compiler.initialize() |
---|
| 226 | env.append_value('CFLAGS_PYEXT',dist_compiler.compile_options) |
---|
| 227 | env.append_value('CXXFLAGS_PYEXT',dist_compiler.compile_options) |
---|
| 228 | env.append_value('LINKFLAGS_PYEXT',dist_compiler.ldflags_shared) |
---|
| 229 | try: |
---|
| 230 | conf.check(header_name='Python.h',define_name='HAVE_PYTHON_H',uselib='PYEMBED',fragment=FRAG,errmsg=':-(') |
---|
| 231 | except conf.errors.ConfigurationError: |
---|
| 232 | xx=conf.env.CXX_NAME and'cxx'or'c' |
---|
[c101fe1] | 233 | flags=['--cflags','--libs','--ldflags'] |
---|
| 234 | for f in flags: |
---|
| 235 | conf.check_cfg(msg='Asking python-config for pyembed %s flags'%f,path=conf.env.PYTHON_CONFIG,package='',uselib_store='PYEMBED',args=[f]) |
---|
[0fa325b] | 236 | 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)) |
---|
[c101fe1] | 237 | for f in flags: |
---|
| 238 | conf.check_cfg(msg='Asking python-config for pyext %s flags'%f,path=conf.env.PYTHON_CONFIG,package='',uselib_store='PYEXT',args=[f]) |
---|
[0fa325b] | 239 | 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') |
---|
| 240 | @conf |
---|
| 241 | def check_python_version(conf,minver=None): |
---|
| 242 | assert minver is None or isinstance(minver,tuple) |
---|
| 243 | pybin=conf.env['PYTHON'] |
---|
| 244 | if not pybin: |
---|
| 245 | conf.fatal('could not find the python executable') |
---|
| 246 | cmd=pybin+['-c','import sys\nfor x in sys.version_info: print(str(x))'] |
---|
| 247 | Logs.debug('python: Running python command %r'%cmd) |
---|
| 248 | lines=conf.cmd_and_log(cmd).split() |
---|
| 249 | assert len(lines)==5,"found %i lines, expected 5: %r"%(len(lines),lines) |
---|
| 250 | pyver_tuple=(int(lines[0]),int(lines[1]),int(lines[2]),lines[3],int(lines[4])) |
---|
| 251 | result=(minver is None)or(pyver_tuple>=minver) |
---|
| 252 | if result: |
---|
| 253 | pyver='.'.join([str(x)for x in pyver_tuple[:2]]) |
---|
| 254 | conf.env['PYTHON_VERSION']=pyver |
---|
| 255 | if'PYTHONDIR'in conf.environ: |
---|
| 256 | pydir=conf.environ['PYTHONDIR'] |
---|
| 257 | else: |
---|
| 258 | if Utils.is_win32: |
---|
| 259 | (python_LIBDEST,pydir)=conf.get_python_variables(["get_config_var('LIBDEST') or ''","get_python_lib(standard_lib=0, prefix=%r) or ''"%conf.env['PREFIX']]) |
---|
| 260 | else: |
---|
| 261 | python_LIBDEST=None |
---|
| 262 | (pydir,)=conf.get_python_variables(["get_python_lib(standard_lib=0, prefix=%r) or ''"%conf.env['PREFIX']]) |
---|
| 263 | if python_LIBDEST is None: |
---|
| 264 | if conf.env['LIBDIR']: |
---|
| 265 | python_LIBDEST=os.path.join(conf.env['LIBDIR'],"python"+pyver) |
---|
| 266 | else: |
---|
| 267 | python_LIBDEST=os.path.join(conf.env['PREFIX'],"lib","python"+pyver) |
---|
| 268 | if'PYTHONARCHDIR'in conf.environ: |
---|
| 269 | pyarchdir=conf.environ['PYTHONARCHDIR'] |
---|
| 270 | else: |
---|
| 271 | (pyarchdir,)=conf.get_python_variables(["get_python_lib(plat_specific=1, standard_lib=0, prefix=%r) or ''"%conf.env['PREFIX']]) |
---|
| 272 | if not pyarchdir: |
---|
| 273 | pyarchdir=pydir |
---|
| 274 | if hasattr(conf,'define'): |
---|
| 275 | conf.define('PYTHONDIR',pydir) |
---|
| 276 | conf.define('PYTHONARCHDIR',pyarchdir) |
---|
| 277 | conf.env['PYTHONDIR']=pydir |
---|
| 278 | conf.env['PYTHONARCHDIR']=pyarchdir |
---|
| 279 | pyver_full='.'.join(map(str,pyver_tuple[:3])) |
---|
| 280 | if minver is None: |
---|
| 281 | conf.msg('Checking for python version',pyver_full) |
---|
| 282 | else: |
---|
| 283 | minver_str='.'.join(map(str,minver)) |
---|
| 284 | conf.msg('Checking for python version',pyver_tuple,">= %s"%(minver_str,)and'GREEN'or'YELLOW') |
---|
| 285 | if not result: |
---|
| 286 | conf.fatal('The python version is too old, expecting %r'%(minver,)) |
---|
| 287 | PYTHON_MODULE_TEMPLATE=''' |
---|
| 288 | import %s as current_module |
---|
| 289 | version = getattr(current_module, '__version__', None) |
---|
| 290 | if version is not None: |
---|
| 291 | print(str(version)) |
---|
| 292 | else: |
---|
| 293 | print('unknown version') |
---|
| 294 | ''' |
---|
| 295 | @conf |
---|
| 296 | def check_python_module(conf,module_name,condition=''): |
---|
| 297 | msg='Python module %s'%module_name |
---|
| 298 | if condition: |
---|
| 299 | msg='%s (%s)'%(msg,condition) |
---|
| 300 | conf.start_msg(msg) |
---|
| 301 | try: |
---|
| 302 | ret=conf.cmd_and_log(conf.env['PYTHON']+['-c',PYTHON_MODULE_TEMPLATE%module_name]) |
---|
| 303 | except Exception: |
---|
| 304 | conf.end_msg(False) |
---|
| 305 | conf.fatal('Could not find the python module %r'%module_name) |
---|
| 306 | ret=ret.strip() |
---|
| 307 | if condition: |
---|
| 308 | conf.end_msg(ret) |
---|
| 309 | if ret=='unknown version': |
---|
| 310 | conf.fatal('Could not check the %s version'%module_name) |
---|
| 311 | from distutils.version import LooseVersion |
---|
| 312 | def num(*k): |
---|
| 313 | if isinstance(k[0],int): |
---|
| 314 | return LooseVersion('.'.join([str(x)for x in k])) |
---|
| 315 | else: |
---|
| 316 | return LooseVersion(k[0]) |
---|
| 317 | d={'num':num,'ver':LooseVersion(ret)} |
---|
| 318 | ev=eval(condition,{},d) |
---|
| 319 | if not ev: |
---|
| 320 | conf.fatal('The %s version does not satisfy the requirements'%module_name) |
---|
| 321 | else: |
---|
| 322 | if ret=='unknown version': |
---|
| 323 | conf.end_msg(True) |
---|
| 324 | else: |
---|
| 325 | conf.end_msg(ret) |
---|
| 326 | def configure(conf): |
---|
| 327 | try: |
---|
| 328 | conf.find_program('python',var='PYTHON') |
---|
| 329 | except conf.errors.ConfigurationError: |
---|
| 330 | Logs.warn("could not find a python executable, setting to sys.executable '%s'"%sys.executable) |
---|
| 331 | conf.env.PYTHON=sys.executable |
---|
| 332 | if conf.env.PYTHON!=sys.executable: |
---|
| 333 | Logs.warn("python executable %r differs from system %r"%(conf.env.PYTHON,sys.executable)) |
---|
| 334 | conf.env.PYTHON=conf.cmd_to_list(conf.env.PYTHON) |
---|
| 335 | v=conf.env |
---|
| 336 | v['PYCMD']='"import sys, py_compile;py_compile.compile(sys.argv[1], sys.argv[2])"' |
---|
| 337 | v['PYFLAGS']='' |
---|
| 338 | v['PYFLAGS_OPT']='-O' |
---|
| 339 | v['PYC']=getattr(Options.options,'pyc',1) |
---|
| 340 | v['PYO']=getattr(Options.options,'pyo',1) |
---|
| 341 | def options(opt): |
---|
| 342 | opt.add_option('--nopyc',action='store_false',default=1,help='Do not install bytecode compiled .pyc files (configuration) [Default:install]',dest='pyc') |
---|
| 343 | opt.add_option('--nopyo',action='store_false',default=1,help='Do not install optimised compiled .pyo files (configuration) [Default:install]',dest='pyo') |
---|