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 |
---|
173 | for name in('python'+env['PYTHON_VERSION'],'python'+env['PYTHON_VERSION']+'m','python'+env['PYTHON_VERSION'].replace('.','')): |
---|
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' |
---|
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]) |
---|
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)) |
---|
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]) |
---|
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') |
---|