jack2 codebase
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

595 lines
20KB

  1. #!/usr/bin/env python
  2. # encoding: utf-8
  3. # Thomas Nagy, 2007-2015 (ita)
  4. # Gustavo Carneiro (gjc), 2007
  5. """
  6. Support for Python, detect the headers and libraries and provide
  7. *use* variables to link C/C++ programs against them::
  8. def options(opt):
  9. opt.load('compiler_c python')
  10. def configure(conf):
  11. conf.load('compiler_c python')
  12. conf.check_python_version((2,4,2))
  13. conf.check_python_headers()
  14. def build(bld):
  15. bld.program(features='pyembed', source='a.c', target='myprog')
  16. bld.shlib(features='pyext', source='b.c', target='mylib')
  17. """
  18. import os, sys
  19. from waflib import Utils, Options, Errors, Logs, Task, Node
  20. from waflib.TaskGen import extension, before_method, after_method, feature
  21. from waflib.Configure import conf
  22. FRAG = '''
  23. #include <Python.h>
  24. #ifdef __cplusplus
  25. extern "C" {
  26. #endif
  27. void Py_Initialize(void);
  28. void Py_Finalize(void);
  29. #ifdef __cplusplus
  30. }
  31. #endif
  32. int main(int argc, char **argv)
  33. {
  34. (void)argc; (void)argv;
  35. Py_Initialize();
  36. Py_Finalize();
  37. return 0;
  38. }
  39. '''
  40. """
  41. Piece of C/C++ code used in :py:func:`waflib.Tools.python.check_python_headers`
  42. """
  43. INST = '''
  44. import sys, py_compile
  45. py_compile.compile(sys.argv[1], sys.argv[2], sys.argv[3], True)
  46. '''
  47. """
  48. Piece of Python code used in :py:func:`waflib.Tools.python.pytask` for byte-compiling python files
  49. """
  50. DISTUTILS_IMP = ['from distutils.sysconfig import get_config_var, get_python_lib']
  51. @before_method('process_source')
  52. @feature('py')
  53. def feature_py(self):
  54. """
  55. Create tasks to byte-compile .py files and install them, if requested
  56. """
  57. self.install_path = getattr(self, 'install_path', '${PYTHONDIR}')
  58. install_from = getattr(self, 'install_from', None)
  59. if install_from and not isinstance(install_from, Node.Node):
  60. install_from = self.path.find_dir(install_from)
  61. self.install_from = install_from
  62. ver = self.env.PYTHON_VERSION
  63. if not ver:
  64. self.bld.fatal('Installing python files requires PYTHON_VERSION, try conf.check_python_version')
  65. if int(ver.replace('.', '')) > 31:
  66. self.install_32 = True
  67. @extension('.py')
  68. def process_py(self, node):
  69. """
  70. Add signature of .py file, so it will be byte-compiled when necessary
  71. """
  72. assert(node.get_bld_sig())
  73. assert(getattr(self, 'install_path')), 'add features="py"'
  74. # where to install the python file
  75. if self.install_path:
  76. if self.install_from:
  77. self.bld.install_files(self.install_path, [node], cwd=self.install_from, relative_trick=True)
  78. else:
  79. self.bld.install_files(self.install_path, [node], relative_trick=True)
  80. lst = []
  81. if self.env.PYC:
  82. lst.append('pyc')
  83. if self.env.PYO:
  84. lst.append('pyo')
  85. if self.install_path:
  86. if self.install_from:
  87. pyd = Utils.subst_vars("%s/%s" % (self.install_path, node.path_from(self.install_from)), self.env)
  88. else:
  89. pyd = Utils.subst_vars("%s/%s" % (self.install_path, node.path_from(self.path)), self.env)
  90. else:
  91. pyd = node.abspath()
  92. for ext in lst:
  93. if self.env.PYTAG:
  94. # __pycache__ installation for python 3.2 - PEP 3147
  95. name = node.name[:-3]
  96. pyobj = node.parent.get_bld().make_node('__pycache__').make_node("%s.%s.%s" % (name, self.env.PYTAG, ext))
  97. pyobj.parent.mkdir()
  98. else:
  99. pyobj = node.change_ext(".%s" % ext)
  100. tsk = self.create_task(ext, node, pyobj)
  101. tsk.pyd = pyd
  102. if self.install_path:
  103. self.bld.install_files(os.path.dirname(pyd), pyobj, cwd=node.parent.get_bld(), relative_trick=True)
  104. class pyc(Task.Task):
  105. """
  106. Byte-compiling python files
  107. """
  108. color = 'PINK'
  109. def run(self):
  110. cmd = [Utils.subst_vars('${PYTHON}', self.env), '-c', INST, self.inputs[0].abspath(), self.outputs[0].abspath(), self.pyd]
  111. ret = self.generator.bld.exec_command(cmd)
  112. return ret
  113. class pyo(Task.Task):
  114. """
  115. Byte-compiling python files
  116. """
  117. color = 'PINK'
  118. def run(self):
  119. 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]
  120. ret = self.generator.bld.exec_command(cmd)
  121. return ret
  122. @feature('pyext')
  123. @before_method('propagate_uselib_vars', 'apply_link')
  124. @after_method('apply_bundle')
  125. def init_pyext(self):
  126. """
  127. Change the values of *cshlib_PATTERN* and *cxxshlib_PATTERN* to remove the
  128. *lib* prefix from library names.
  129. """
  130. self.uselib = self.to_list(getattr(self, 'uselib', []))
  131. if not 'PYEXT' in self.uselib:
  132. self.uselib.append('PYEXT')
  133. # override shlib_PATTERN set by the osx module
  134. self.env.cshlib_PATTERN = self.env.cxxshlib_PATTERN = self.env.macbundle_PATTERN = self.env.pyext_PATTERN
  135. self.env.fcshlib_PATTERN = self.env.dshlib_PATTERN = self.env.pyext_PATTERN
  136. try:
  137. if not self.install_path:
  138. return
  139. except AttributeError:
  140. self.install_path = '${PYTHONARCHDIR}'
  141. @feature('pyext')
  142. @before_method('apply_link', 'apply_bundle')
  143. def set_bundle(self):
  144. """Mac-specific pyext extension that enables bundles from c_osx.py"""
  145. if Utils.unversioned_sys_platform() == 'darwin':
  146. self.mac_bundle = True
  147. @before_method('propagate_uselib_vars')
  148. @feature('pyembed')
  149. def init_pyembed(self):
  150. """
  151. Add the PYEMBED variable.
  152. """
  153. self.uselib = self.to_list(getattr(self, 'uselib', []))
  154. if not 'PYEMBED' in self.uselib:
  155. self.uselib.append('PYEMBED')
  156. @conf
  157. def get_python_variables(self, variables, imports=None):
  158. """
  159. Spawn a new python process to dump configuration variables
  160. :param variables: variables to print
  161. :type variables: list of string
  162. :param imports: one import by element
  163. :type imports: list of string
  164. :return: the variable values
  165. :rtype: list of string
  166. """
  167. if not imports:
  168. try:
  169. imports = self.python_imports
  170. except AttributeError:
  171. imports = DISTUTILS_IMP
  172. program = list(imports) # copy
  173. program.append('')
  174. for v in variables:
  175. program.append("print(repr(%s))" % v)
  176. os_env = dict(os.environ)
  177. try:
  178. del os_env['MACOSX_DEPLOYMENT_TARGET'] # see comments in the OSX tool
  179. except KeyError:
  180. pass
  181. try:
  182. out = self.cmd_and_log(self.env.PYTHON + ['-c', '\n'.join(program)], env=os_env)
  183. except Errors.WafError:
  184. self.fatal('The distutils module is unusable: install "python-devel"?')
  185. self.to_log(out)
  186. return_values = []
  187. for s in out.splitlines():
  188. s = s.strip()
  189. if not s:
  190. continue
  191. if s == 'None':
  192. return_values.append(None)
  193. elif (s[0] == "'" and s[-1] == "'") or (s[0] == '"' and s[-1] == '"'):
  194. return_values.append(eval(s))
  195. elif s[0].isdigit():
  196. return_values.append(int(s))
  197. else: break
  198. return return_values
  199. @conf
  200. def python_cross_compile(self, features='pyembed pyext'):
  201. """
  202. For cross-compilation purposes, it is possible to bypass the normal detection and set the flags that you want:
  203. PYTHON_VERSION='3.4' PYTAG='cpython34' pyext_PATTERN="%s.so" PYTHON_LDFLAGS='-lpthread -ldl' waf configure
  204. The following variables are used:
  205. PYTHON_VERSION required
  206. PYTAG required
  207. PYTHON_LDFLAGS required
  208. pyext_PATTERN required
  209. PYTHON_PYEXT_LDFLAGS
  210. PYTHON_PYEMBED_LDFLAGS
  211. """
  212. features = Utils.to_list(features)
  213. if not ('PYTHON_LDFLAGS' in self.environ or 'PYTHON_PYEXT_LDFLAGS' in self.environ or 'PYTHON_PYEMBED_LDFLAGS' in self.environ):
  214. return False
  215. for x in 'PYTHON_VERSION PYTAG pyext_PATTERN'.split():
  216. if not x in self.environ:
  217. self.fatal('Please set %s in the os environment' % x)
  218. else:
  219. self.env[x] = self.environ[x]
  220. xx = self.env.CXX_NAME and 'cxx' or 'c'
  221. if 'pyext' in features:
  222. flags = self.environ.get('PYTHON_PYEXT_LDFLAGS', self.environ.get('PYTHON_LDFLAGS', None))
  223. if flags is None:
  224. self.fatal('No flags provided through PYTHON_PYEXT_LDFLAGS as required')
  225. else:
  226. self.parse_flags(flags, 'PYEXT')
  227. self.check(header_name='Python.h', define_name='HAVE_PYEXT', msg='Testing pyext configuration',
  228. features='%s %sshlib pyext' % (xx, xx), fragment=FRAG, errmsg='Could not build python extensions')
  229. if 'pyembed' in features:
  230. flags = self.environ.get('PYTHON_PYEMBED_LDFLAGS', self.environ.get('PYTHON_LDFLAGS', None))
  231. if flags is None:
  232. self.fatal('No flags provided through PYTHON_PYEMBED_LDFLAGS as required')
  233. else:
  234. self.parse_flags(flags, 'PYEMBED')
  235. self.check(header_name='Python.h', define_name='HAVE_PYEMBED', msg='Testing pyembed configuration',
  236. fragment=FRAG, errmsg='Could not build a python embedded interpreter', features='%s %sprogram pyembed' % (xx, xx))
  237. return True
  238. @conf
  239. def check_python_headers(conf, features='pyembed pyext'):
  240. """
  241. Check for headers and libraries necessary to extend or embed python by using the module *distutils*.
  242. On success the environment variables xxx_PYEXT and xxx_PYEMBED are added:
  243. * PYEXT: for compiling python extensions
  244. * PYEMBED: for embedding a python interpreter
  245. """
  246. features = Utils.to_list(features)
  247. assert ('pyembed' in features) or ('pyext' in features), "check_python_headers features must include 'pyembed' and/or 'pyext'"
  248. env = conf.env
  249. if not env['CC_NAME'] and not env['CXX_NAME']:
  250. conf.fatal('load a compiler first (gcc, g++, ..)')
  251. # bypass all the code below for cross-compilation
  252. if conf.python_cross_compile(features):
  253. return
  254. if not env['PYTHON_VERSION']:
  255. conf.check_python_version()
  256. pybin = env.PYTHON
  257. if not pybin:
  258. conf.fatal('Could not find the python executable')
  259. # so we actually do all this for compatibility reasons and for obtaining pyext_PATTERN below
  260. v = 'prefix SO LDFLAGS LIBDIR LIBPL INCLUDEPY Py_ENABLE_SHARED MACOSX_DEPLOYMENT_TARGET LDSHARED CFLAGS LDVERSION'.split()
  261. try:
  262. lst = conf.get_python_variables(["get_config_var('%s') or ''" % x for x in v])
  263. except RuntimeError:
  264. conf.fatal("Python development headers not found (-v for details).")
  265. vals = ['%s = %r' % (x, y) for (x, y) in zip(v, lst)]
  266. conf.to_log("Configuration returned from %r:\n%s\n" % (pybin, '\n'.join(vals)))
  267. dct = dict(zip(v, lst))
  268. x = 'MACOSX_DEPLOYMENT_TARGET'
  269. if dct[x]:
  270. env[x] = conf.environ[x] = dct[x]
  271. env['pyext_PATTERN'] = '%s' + dct['SO'] # not a mistake
  272. # Try to get pythonX.Y-config
  273. num = '.'.join(env['PYTHON_VERSION'].split('.')[:2])
  274. 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)
  275. if env.PYTHON_CONFIG:
  276. # python2.6-config requires 3 runs
  277. all_flags = [['--cflags', '--libs', '--ldflags']]
  278. if sys.hexversion < 0x2070000:
  279. all_flags = [[k] for k in all_flags[0]]
  280. xx = env.CXX_NAME and 'cxx' or 'c'
  281. if 'pyembed' in features:
  282. for flags in all_flags:
  283. conf.check_cfg(msg='Asking python-config for pyembed %r flags' % ' '.join(flags), path=env.PYTHON_CONFIG, package='', uselib_store='PYEMBED', args=flags)
  284. conf.check(header_name='Python.h', define_name='HAVE_PYEMBED', msg='Getting pyembed flags from python-config',
  285. fragment=FRAG, errmsg='Could not build a python embedded interpreter',
  286. features='%s %sprogram pyembed' % (xx, xx))
  287. if 'pyext' in features:
  288. for flags in all_flags:
  289. conf.check_cfg(msg='Asking python-config for pyext %r flags' % ' '.join(flags), path=env.PYTHON_CONFIG, package='', uselib_store='PYEXT', args=flags)
  290. conf.check(header_name='Python.h', define_name='HAVE_PYEXT', msg='Getting pyext flags from python-config',
  291. features='%s %sshlib pyext' % (xx, xx), fragment=FRAG, errmsg='Could not build python extensions')
  292. conf.define('HAVE_PYTHON_H', 1)
  293. return
  294. # No python-config, do something else on windows systems
  295. all_flags = dct['LDFLAGS'] + ' ' + dct['CFLAGS']
  296. conf.parse_flags(all_flags, 'PYEMBED')
  297. all_flags = dct['LDFLAGS'] + ' ' + dct['LDSHARED'] + ' ' + dct['CFLAGS']
  298. conf.parse_flags(all_flags, 'PYEXT')
  299. result = None
  300. if not dct["LDVERSION"]:
  301. dct["LDVERSION"] = env['PYTHON_VERSION']
  302. # further simplification will be complicated
  303. for name in ('python' + dct['LDVERSION'], 'python' + env['PYTHON_VERSION'] + 'm', 'python' + env['PYTHON_VERSION'].replace('.', '')):
  304. # LIBPATH_PYEMBED is already set; see if it works.
  305. if not result and env['LIBPATH_PYEMBED']:
  306. path = env['LIBPATH_PYEMBED']
  307. conf.to_log("\n\n# Trying default LIBPATH_PYEMBED: %r\n" % path)
  308. result = conf.check(lib=name, uselib='PYEMBED', libpath=path, mandatory=False, msg='Checking for library %s in LIBPATH_PYEMBED' % name)
  309. if not result and dct['LIBDIR']:
  310. path = [dct['LIBDIR']]
  311. conf.to_log("\n\n# try again with -L$python_LIBDIR: %r\n" % path)
  312. result = conf.check(lib=name, uselib='PYEMBED', libpath=path, mandatory=False, msg='Checking for library %s in LIBDIR' % name)
  313. if not result and dct['LIBPL']:
  314. path = [dct['LIBPL']]
  315. conf.to_log("\n\n# try again with -L$python_LIBPL (some systems don't install the python library in $prefix/lib)\n")
  316. result = conf.check(lib=name, uselib='PYEMBED', libpath=path, mandatory=False, msg='Checking for library %s in python_LIBPL' % name)
  317. if not result:
  318. path = [os.path.join(dct['prefix'], "libs")]
  319. conf.to_log("\n\n# try again with -L$prefix/libs, and pythonXY name rather than pythonX.Y (win32)\n")
  320. result = conf.check(lib=name, uselib='PYEMBED', libpath=path, mandatory=False, msg='Checking for library %s in $prefix/libs' % name)
  321. if result:
  322. break # do not forget to set LIBPATH_PYEMBED
  323. if result:
  324. env['LIBPATH_PYEMBED'] = path
  325. env.append_value('LIB_PYEMBED', [name])
  326. else:
  327. conf.to_log("\n\n### LIB NOT FOUND\n")
  328. # under certain conditions, python extensions must link to
  329. # python libraries, not just python embedding programs.
  330. if Utils.is_win32 or dct['Py_ENABLE_SHARED']:
  331. env['LIBPATH_PYEXT'] = env['LIBPATH_PYEMBED']
  332. env['LIB_PYEXT'] = env['LIB_PYEMBED']
  333. conf.to_log("Include path for Python extensions (found via distutils module): %r\n" % (dct['INCLUDEPY'],))
  334. env['INCLUDES_PYEXT'] = [dct['INCLUDEPY']]
  335. env['INCLUDES_PYEMBED'] = [dct['INCLUDEPY']]
  336. # Code using the Python API needs to be compiled with -fno-strict-aliasing
  337. if env['CC_NAME'] == 'gcc':
  338. env.append_value('CFLAGS_PYEMBED', ['-fno-strict-aliasing'])
  339. env.append_value('CFLAGS_PYEXT', ['-fno-strict-aliasing'])
  340. if env['CXX_NAME'] == 'gcc':
  341. env.append_value('CXXFLAGS_PYEMBED', ['-fno-strict-aliasing'])
  342. env.append_value('CXXFLAGS_PYEXT', ['-fno-strict-aliasing'])
  343. if env.CC_NAME == "msvc":
  344. from distutils.msvccompiler import MSVCCompiler
  345. dist_compiler = MSVCCompiler()
  346. dist_compiler.initialize()
  347. env.append_value('CFLAGS_PYEXT', dist_compiler.compile_options)
  348. env.append_value('CXXFLAGS_PYEXT', dist_compiler.compile_options)
  349. env.append_value('LINKFLAGS_PYEXT', dist_compiler.ldflags_shared)
  350. # See if it compiles
  351. 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!')
  352. @conf
  353. def check_python_version(conf, minver=None):
  354. """
  355. Check if the python interpreter is found matching a given minimum version.
  356. minver should be a tuple, eg. to check for python >= 2.4.2 pass (2,4,2) as minver.
  357. If successful, PYTHON_VERSION is defined as 'MAJOR.MINOR'
  358. (eg. '2.4') of the actual python version found, and PYTHONDIR is
  359. defined, pointing to the site-packages directory appropriate for
  360. this python version, where modules/packages/extensions should be
  361. installed.
  362. :param minver: minimum version
  363. :type minver: tuple of int
  364. """
  365. assert minver is None or isinstance(minver, tuple)
  366. pybin = conf.env['PYTHON']
  367. if not pybin:
  368. conf.fatal('could not find the python executable')
  369. # Get python version string
  370. cmd = pybin + ['-c', 'import sys\nfor x in sys.version_info: print(str(x))']
  371. Logs.debug('python: Running python command %r' % cmd)
  372. lines = conf.cmd_and_log(cmd).split()
  373. assert len(lines) == 5, "found %i lines, expected 5: %r" % (len(lines), lines)
  374. pyver_tuple = (int(lines[0]), int(lines[1]), int(lines[2]), lines[3], int(lines[4]))
  375. # compare python version with the minimum required
  376. result = (minver is None) or (pyver_tuple >= minver)
  377. if result:
  378. # define useful environment variables
  379. pyver = '.'.join([str(x) for x in pyver_tuple[:2]])
  380. conf.env['PYTHON_VERSION'] = pyver
  381. if 'PYTHONDIR' in conf.env:
  382. # Check if --pythondir was specified
  383. pydir = conf.env['PYTHONDIR']
  384. elif 'PYTHONDIR' in conf.environ:
  385. # Check environment for PYTHONDIR
  386. pydir = conf.environ['PYTHONDIR']
  387. else:
  388. # Finally, try to guess
  389. if Utils.is_win32:
  390. (python_LIBDEST, pydir) = conf.get_python_variables(
  391. ["get_config_var('LIBDEST') or ''",
  392. "get_python_lib(standard_lib=0) or ''"])
  393. else:
  394. python_LIBDEST = None
  395. (pydir,) = conf.get_python_variables( ["get_python_lib(standard_lib=0, prefix='%s') or ''" % conf.env['PREFIX']])
  396. if python_LIBDEST is None:
  397. if conf.env['LIBDIR']:
  398. python_LIBDEST = os.path.join(conf.env['LIBDIR'], "python" + pyver)
  399. else:
  400. python_LIBDEST = os.path.join(conf.env['PREFIX'], "lib", "python" + pyver)
  401. if 'PYTHONARCHDIR' in conf.env:
  402. # Check if --pythonarchdir was specified
  403. pyarchdir = conf.env['PYTHONARCHDIR']
  404. elif 'PYTHONARCHDIR' in conf.environ:
  405. # Check environment for PYTHONDIR
  406. pyarchdir = conf.environ['PYTHONARCHDIR']
  407. else:
  408. # Finally, try to guess
  409. (pyarchdir, ) = conf.get_python_variables( ["get_python_lib(plat_specific=1, standard_lib=0, prefix='%s') or ''" % conf.env['PREFIX']])
  410. if not pyarchdir:
  411. pyarchdir = pydir
  412. if hasattr(conf, 'define'): # conf.define is added by the C tool, so may not exist
  413. conf.define('PYTHONDIR', pydir)
  414. conf.define('PYTHONARCHDIR', pyarchdir)
  415. conf.env['PYTHONDIR'] = pydir
  416. conf.env['PYTHONARCHDIR'] = pyarchdir
  417. # Feedback
  418. pyver_full = '.'.join(map(str, pyver_tuple[:3]))
  419. if minver is None:
  420. conf.msg('Checking for python version', pyver_full)
  421. else:
  422. minver_str = '.'.join(map(str, minver))
  423. conf.msg('Checking for python version', pyver_tuple, ">= %s" % (minver_str,) and 'GREEN' or 'YELLOW')
  424. if not result:
  425. conf.fatal('The python version is too old, expecting %r' % (minver,))
  426. PYTHON_MODULE_TEMPLATE = '''
  427. import %s as current_module
  428. version = getattr(current_module, '__version__', None)
  429. if version is not None:
  430. print(str(version))
  431. else:
  432. print('unknown version')
  433. '''
  434. @conf
  435. def check_python_module(conf, module_name, condition=''):
  436. """
  437. Check if the selected python interpreter can import the given python module::
  438. def configure(conf):
  439. conf.check_python_module('pygccxml')
  440. conf.check_python_module('re', condition="ver > num(2, 0, 4) and ver <= num(3, 0, 0)")
  441. :param module_name: module
  442. :type module_name: string
  443. """
  444. msg = "Checking for python module '%s'" % module_name
  445. if condition:
  446. msg = '%s (%s)' % (msg, condition)
  447. conf.start_msg(msg)
  448. try:
  449. ret = conf.cmd_and_log(conf.env['PYTHON'] + ['-c', PYTHON_MODULE_TEMPLATE % module_name])
  450. except Exception:
  451. conf.end_msg(False)
  452. conf.fatal('Could not find the python module %r' % module_name)
  453. ret = ret.strip()
  454. if condition:
  455. conf.end_msg(ret)
  456. if ret == 'unknown version':
  457. conf.fatal('Could not check the %s version' % module_name)
  458. from distutils.version import LooseVersion
  459. def num(*k):
  460. if isinstance(k[0], int):
  461. return LooseVersion('.'.join([str(x) for x in k]))
  462. else:
  463. return LooseVersion(k[0])
  464. d = {'num': num, 'ver': LooseVersion(ret)}
  465. ev = eval(condition, {}, d)
  466. if not ev:
  467. conf.fatal('The %s version does not satisfy the requirements' % module_name)
  468. else:
  469. if ret == 'unknown version':
  470. conf.end_msg(True)
  471. else:
  472. conf.end_msg(ret)
  473. def configure(conf):
  474. """
  475. Detect the python interpreter
  476. """
  477. v = conf.env
  478. v['PYTHON'] = Options.options.python or os.environ.get('PYTHON', sys.executable)
  479. if Options.options.pythondir:
  480. v['PYTHONDIR'] = Options.options.pythondir
  481. if Options.options.pythonarchdir:
  482. v['PYTHONARCHDIR'] = Options.options.pythonarchdir
  483. conf.find_program('python', var='PYTHON')
  484. v['PYFLAGS'] = ''
  485. v['PYFLAGS_OPT'] = '-O'
  486. v['PYC'] = getattr(Options.options, 'pyc', 1)
  487. v['PYO'] = getattr(Options.options, 'pyo', 1)
  488. try:
  489. v.PYTAG = conf.cmd_and_log(conf.env.PYTHON + ['-c', "import imp;print(imp.get_tag())"]).strip()
  490. except Errors.WafError:
  491. pass
  492. def options(opt):
  493. """
  494. Add python-specific options
  495. """
  496. pyopt=opt.add_option_group("Python Options")
  497. pyopt.add_option('--nopyc', dest = 'pyc', action='store_false', default=1,
  498. help = 'Do not install bytecode compiled .pyc files (configuration) [Default:install]')
  499. pyopt.add_option('--nopyo', dest='pyo', action='store_false', default=1,
  500. help='Do not install optimised compiled .pyo files (configuration) [Default:install]')
  501. pyopt.add_option('--python', dest="python",
  502. help='python binary to be used [Default: %s]' % sys.executable)
  503. pyopt.add_option('--pythondir', dest='pythondir',
  504. help='Installation path for python modules (py, platform-independent .py and .pyc files)')
  505. pyopt.add_option('--pythonarchdir', dest='pythonarchdir',
  506. help='Installation path for python extension (pyext, platform-dependent .so or .dylib files)')