2008-07-08 10:43:58 -07:00
|
|
|
## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
|
2010-11-07 23:17:52 +00:00
|
|
|
import types
|
2008-07-08 10:43:58 -07:00
|
|
|
import re
|
|
|
|
|
import os
|
2011-09-08 16:13:40 +01:00
|
|
|
import subprocess
|
2008-07-08 10:43:58 -07:00
|
|
|
import shutil
|
2008-09-04 18:45:21 +01:00
|
|
|
import sys
|
2008-07-08 10:43:58 -07:00
|
|
|
|
2008-12-29 13:28:54 +00:00
|
|
|
import Task
|
|
|
|
|
import Options
|
|
|
|
|
import Configure
|
|
|
|
|
import TaskGen
|
|
|
|
|
import Logs
|
|
|
|
|
import Build
|
2008-12-29 15:48:34 +00:00
|
|
|
import Utils
|
2008-12-29 13:28:54 +00:00
|
|
|
|
2008-07-08 10:43:58 -07:00
|
|
|
## https://launchpad.net/pybindgen/
|
2011-08-07 16:52:49 +01:00
|
|
|
REQUIRED_PYBINDGEN_VERSION = (0, 15, 0, 795)
|
2008-07-08 10:43:58 -07:00
|
|
|
REQUIRED_PYGCCXML_VERSION = (0, 9, 5)
|
|
|
|
|
|
|
|
|
|
|
2010-03-17 12:34:52 +00:00
|
|
|
|
|
|
|
|
from TaskGen import feature, after
|
2011-09-08 16:13:40 +01:00
|
|
|
import Task
|
|
|
|
|
#from python import _get_python_variables # this comes from wafadmin/Tools/python.py
|
2010-03-17 12:34:52 +00:00
|
|
|
|
2011-09-08 16:13:40 +01:00
|
|
|
if 0:
|
|
|
|
|
# Patch a bug in waf-1.5.16's python detection, see
|
|
|
|
|
# https://www.nsnam.org/bugzilla/show_bug.cgi?id=1250
|
|
|
|
|
import python
|
|
|
|
|
python.FRAG_2 = """
|
|
|
|
|
#include <Python.h>
|
|
|
|
|
""" + python.FRAG_2
|
|
|
|
|
del python
|
2011-08-25 19:24:06 +01:00
|
|
|
|
|
|
|
|
|
2010-03-17 12:34:52 +00:00
|
|
|
|
2008-11-19 17:32:37 +00:00
|
|
|
def add_to_python_path(path):
|
|
|
|
|
if os.environ.get('PYTHONPATH', ''):
|
|
|
|
|
os.environ['PYTHONPATH'] = path + os.pathsep + os.environ.get('PYTHONPATH')
|
|
|
|
|
else:
|
|
|
|
|
os.environ['PYTHONPATH'] = path
|
|
|
|
|
|
|
|
|
|
def set_pybindgen_pythonpath(env):
|
|
|
|
|
if env['WITH_PYBINDGEN']:
|
|
|
|
|
add_to_python_path(env['WITH_PYBINDGEN'])
|
|
|
|
|
|
|
|
|
|
|
2008-07-08 10:43:58 -07:00
|
|
|
def set_options(opt):
|
|
|
|
|
opt.tool_options('python')
|
2008-09-06 14:46:01 +01:00
|
|
|
opt.add_option('--disable-python',
|
2008-07-08 10:43:58 -07:00
|
|
|
help=("Don't build Python bindings."),
|
|
|
|
|
action="store_true", default=False,
|
|
|
|
|
dest='python_disable')
|
|
|
|
|
opt.add_option('--python-scan',
|
|
|
|
|
help=("Rescan Python bindings. Needs working GCCXML / pygccxml environment."),
|
|
|
|
|
action="store_true", default=False,
|
|
|
|
|
dest='python_scan')
|
2010-11-07 23:17:52 +00:00
|
|
|
opt.add_option('--apiscan',
|
2011-03-20 15:41:43 +00:00
|
|
|
help=("EXPERIMENTAL: Rescan the API for the indicated module(s), for Python bindings. "
|
|
|
|
|
"Needs working GCCXML / pygccxml environment. "
|
|
|
|
|
"The metamodule 'all' expands to all available ns-3 modules."),
|
2010-11-07 23:17:52 +00:00
|
|
|
default=None, dest='apiscan', metavar="MODULE[,MODULE...]")
|
2008-11-19 17:32:37 +00:00
|
|
|
opt.add_option('--with-pybindgen',
|
|
|
|
|
help=('Path to an existing pybindgen source tree to use.'),
|
|
|
|
|
default=None,
|
|
|
|
|
dest='with_pybindgen', type="string")
|
2008-07-08 10:43:58 -07:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def configure(conf):
|
|
|
|
|
conf.env['ENABLE_PYTHON_BINDINGS'] = False
|
2008-12-29 13:28:54 +00:00
|
|
|
if Options.options.python_disable:
|
2008-09-05 18:16:29 +01:00
|
|
|
conf.report_optional_feature("python", "Python Bindings", False,
|
|
|
|
|
"disabled by user request")
|
2008-07-08 10:43:58 -07:00
|
|
|
return
|
2011-08-31 06:23:28 -07:00
|
|
|
# Disable python in static builds (bug #1253)
|
|
|
|
|
if ((conf.env['ENABLE_STATIC_NS3']) or \
|
|
|
|
|
(conf.env['ENABLE_SHARED_AND_STATIC_NS3'])):
|
|
|
|
|
conf.report_optional_feature("python", "Python Bindings", False,
|
|
|
|
|
"bindings incompatible with static build")
|
|
|
|
|
return
|
2008-07-08 10:43:58 -07:00
|
|
|
|
2011-03-20 13:01:40 +00:00
|
|
|
enabled_modules = list(conf.env['NS3_ENABLED_MODULES'])
|
|
|
|
|
enabled_modules.sort()
|
|
|
|
|
available_modules = list(conf.env['NS3_MODULES'])
|
|
|
|
|
available_modules.sort()
|
|
|
|
|
all_modules_enabled = (enabled_modules == available_modules)
|
|
|
|
|
|
2011-09-08 16:13:40 +01:00
|
|
|
conf.check_tool('misc', tooldir=['waf-tools'])
|
2008-07-08 10:43:58 -07:00
|
|
|
|
2009-09-25 12:15:27 +01:00
|
|
|
if sys.platform == 'cygwin':
|
|
|
|
|
conf.report_optional_feature("python", "Python Bindings", False,
|
|
|
|
|
"unsupported platform 'cygwin'")
|
|
|
|
|
Logs.warn("Python is not supported in CygWin environment. Try MingW instead.")
|
|
|
|
|
return
|
2008-09-04 18:45:21 +01:00
|
|
|
|
2008-07-08 10:43:58 -07:00
|
|
|
## Check for Python
|
|
|
|
|
try:
|
|
|
|
|
conf.check_tool('python')
|
2008-07-22 16:54:24 +01:00
|
|
|
conf.check_python_version((2,3))
|
2008-07-08 10:43:58 -07:00
|
|
|
conf.check_python_headers()
|
2008-09-05 18:16:29 +01:00
|
|
|
except Configure.ConfigurationError, ex:
|
|
|
|
|
conf.report_optional_feature("python", "Python Bindings", False, str(ex))
|
2008-07-08 10:43:58 -07:00
|
|
|
return
|
|
|
|
|
|
2011-07-11 14:24:59 +01:00
|
|
|
|
2011-09-08 16:13:40 +01:00
|
|
|
if 0:
|
|
|
|
|
# alternative code to computing PYTHONDIR, that is more correct than the one in waf 1.5.16
|
|
|
|
|
if 'PYTHONDIR' in conf.environ:
|
|
|
|
|
pydir = conf.environ['PYTHONDIR']
|
|
|
|
|
else:
|
|
|
|
|
(pydir,) = _get_python_variables(conf.env['PYTHON'],
|
|
|
|
|
["get_python_lib(plat_specific=1, standard_lib=0, prefix=%r)" % conf.env['PREFIX']],
|
|
|
|
|
['from distutils.sysconfig import get_python_lib'])
|
|
|
|
|
if hasattr(conf, 'define'): # conf.define is added by the C tool, so may not exist
|
|
|
|
|
conf.define('PYTHONDIR', pydir)
|
|
|
|
|
conf.env['PYTHONDIR'] = pydir
|
2011-07-11 14:24:59 +01:00
|
|
|
|
|
|
|
|
|
2009-03-03 18:51:16 +00:00
|
|
|
# -fvisibility=hidden optimization
|
2009-04-30 10:57:30 +01:00
|
|
|
if (conf.env['CXX_NAME'] == 'gcc' and [int(x) for x in conf.env['CC_VERSION']] >= [4,0,0]
|
|
|
|
|
and conf.check_compilation_flag('-fvisibility=hidden')):
|
2009-03-03 18:51:16 +00:00
|
|
|
conf.env.append_value('CXXFLAGS_PYEXT', '-fvisibility=hidden')
|
|
|
|
|
conf.env.append_value('CCFLAGS_PYEXT', '-fvisibility=hidden')
|
|
|
|
|
|
2009-01-24 15:28:54 +00:00
|
|
|
# Check for the location of pybindgen
|
|
|
|
|
if Options.options.with_pybindgen is not None:
|
|
|
|
|
if os.path.isdir(Options.options.with_pybindgen):
|
2011-09-08 16:13:40 +01:00
|
|
|
conf.msg("Checking for pybindgen location", ("%s (given)" % Options.options.with_pybindgen))
|
2009-01-24 15:28:54 +00:00
|
|
|
conf.env['WITH_PYBINDGEN'] = os.path.abspath(Options.options.with_pybindgen)
|
|
|
|
|
else:
|
2010-08-20 12:17:19 -07:00
|
|
|
# ns-3-dev uses ../pybindgen, while ns-3 releases use ../REQUIRED_PYBINDGEN_VERSION
|
2009-01-24 15:28:54 +00:00
|
|
|
pybindgen_dir = os.path.join('..', "pybindgen")
|
2010-08-20 12:17:19 -07:00
|
|
|
pybindgen_release_str = "pybindgen-" + '.'.join([str(x) for x in REQUIRED_PYBINDGEN_VERSION])
|
|
|
|
|
pybindgen_release_dir = os.path.join('..', pybindgen_release_str)
|
2009-01-24 15:28:54 +00:00
|
|
|
if os.path.isdir(pybindgen_dir):
|
2011-09-08 16:13:40 +01:00
|
|
|
conf.msg("Checking for pybindgen location", ("%s (guessed)" % pybindgen_dir))
|
2009-01-24 15:28:54 +00:00
|
|
|
conf.env['WITH_PYBINDGEN'] = os.path.abspath(pybindgen_dir)
|
2010-08-20 12:17:19 -07:00
|
|
|
elif os.path.isdir(pybindgen_release_dir):
|
2011-09-08 16:13:40 +01:00
|
|
|
conf.msg("Checking for pybindgen location", ("%s (guessed)" % pybindgen_release_dir))
|
2010-08-20 12:17:19 -07:00
|
|
|
conf.env['WITH_PYBINDGEN'] = os.path.abspath(pybindgen_release_dir)
|
2009-01-24 15:28:54 +00:00
|
|
|
del pybindgen_dir
|
2010-08-20 12:17:19 -07:00
|
|
|
del pybindgen_release_dir
|
2009-01-24 15:28:54 +00:00
|
|
|
if not conf.env['WITH_PYBINDGEN']:
|
2011-09-08 16:13:40 +01:00
|
|
|
conf.msg("pybindgen location", False)
|
2008-11-19 17:32:37 +00:00
|
|
|
|
2009-01-24 15:28:54 +00:00
|
|
|
# Check for pybindgen
|
2008-11-19 17:32:37 +00:00
|
|
|
|
|
|
|
|
set_pybindgen_pythonpath(conf.env)
|
|
|
|
|
|
2008-07-08 10:43:58 -07:00
|
|
|
try:
|
|
|
|
|
conf.check_python_module('pybindgen')
|
|
|
|
|
except Configure.ConfigurationError:
|
2009-01-11 23:26:34 +00:00
|
|
|
Logs.warn("pybindgen missing => no python bindings")
|
|
|
|
|
conf.report_optional_feature("python", "Python Bindings", False,
|
|
|
|
|
"PyBindGen missing")
|
2009-01-12 18:45:03 +00:00
|
|
|
return
|
2008-07-08 10:43:58 -07:00
|
|
|
else:
|
2011-09-08 16:13:40 +01:00
|
|
|
out = subprocess.Popen([conf.env['PYTHON'][0], "-c",
|
2008-07-08 10:43:58 -07:00
|
|
|
"import pybindgen.version; "
|
|
|
|
|
"print '.'.join([str(x) for x in pybindgen.version.__version__])"],
|
|
|
|
|
stdout=subprocess.PIPE).communicate()[0]
|
|
|
|
|
pybindgen_version_str = out.strip()
|
|
|
|
|
pybindgen_version = tuple([int(x) for x in pybindgen_version_str.split('.')])
|
2011-09-08 16:13:40 +01:00
|
|
|
conf.msg('Checking for pybindgen version', pybindgen_version_str)
|
2009-05-24 11:39:41 +01:00
|
|
|
if not (pybindgen_version == REQUIRED_PYBINDGEN_VERSION):
|
|
|
|
|
Logs.warn("pybindgen (found %s), (need %s)" %
|
2008-07-08 10:43:58 -07:00
|
|
|
(pybindgen_version_str,
|
|
|
|
|
'.'.join([str(x) for x in REQUIRED_PYBINDGEN_VERSION])))
|
2009-01-24 15:28:54 +00:00
|
|
|
conf.report_optional_feature("python", "Python Bindings", False,
|
2009-05-24 11:39:41 +01:00
|
|
|
"PyBindGen version not correct and newer version could not be retrieved")
|
2009-01-24 15:28:54 +00:00
|
|
|
return
|
2008-07-08 10:43:58 -07:00
|
|
|
|
2009-11-22 18:27:14 +00:00
|
|
|
|
|
|
|
|
def test(t1, t2):
|
|
|
|
|
test_program = '''
|
|
|
|
|
#include <stdint.h>
|
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
|
|
int main ()
|
|
|
|
|
{
|
|
|
|
|
std::vector< %(type1)s > t = std::vector< %(type2)s > ();
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
''' % dict(type1=t1, type2=t2)
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
ret = conf.run_c_code(code=test_program,
|
|
|
|
|
env=conf.env.copy(), compile_filename='test.cc',
|
2011-09-08 16:13:40 +01:00
|
|
|
features='cxx cprogram', execute=False)
|
2009-11-22 18:27:14 +00:00
|
|
|
except Configure.ConfigurationError:
|
|
|
|
|
ret = 1
|
2011-09-08 16:13:40 +01:00
|
|
|
conf.msg('Checking for types %s and %s equivalence' % (t1, t2), (ret and 'no' or 'yes'))
|
2009-11-22 18:27:14 +00:00
|
|
|
return not ret
|
|
|
|
|
|
|
|
|
|
uint64_is_long = test("uint64_t", "unsigned long")
|
|
|
|
|
uint64_is_long_long = test("uint64_t", "unsigned long long")
|
|
|
|
|
|
|
|
|
|
if uint64_is_long:
|
|
|
|
|
conf.env['PYTHON_BINDINGS_APIDEFS'] = 'gcc-LP64'
|
|
|
|
|
elif uint64_is_long_long:
|
|
|
|
|
conf.env['PYTHON_BINDINGS_APIDEFS'] = 'gcc-ILP32'
|
|
|
|
|
else:
|
|
|
|
|
conf.env['PYTHON_BINDINGS_APIDEFS'] = None
|
|
|
|
|
if conf.env['PYTHON_BINDINGS_APIDEFS'] is None:
|
|
|
|
|
msg = 'none available'
|
|
|
|
|
else:
|
|
|
|
|
msg = conf.env['PYTHON_BINDINGS_APIDEFS']
|
|
|
|
|
|
2011-09-08 16:13:40 +01:00
|
|
|
conf.msg('Checking for the apidefs that can be used for Python bindings', msg)
|
2009-11-22 18:27:14 +00:00
|
|
|
|
|
|
|
|
if conf.env['PYTHON_BINDINGS_APIDEFS'] is None:
|
|
|
|
|
conf.report_optional_feature("python", "Python Bindings", False,
|
|
|
|
|
"No apidefs are available that can be used in this system")
|
|
|
|
|
return
|
|
|
|
|
|
2011-03-20 13:01:40 +00:00
|
|
|
|
2008-07-08 10:43:58 -07:00
|
|
|
## If all has gone well, we finally enable the Python bindings
|
|
|
|
|
conf.env['ENABLE_PYTHON_BINDINGS'] = True
|
2008-09-05 18:16:29 +01:00
|
|
|
conf.report_optional_feature("python", "Python Bindings", True, None)
|
2008-07-08 10:43:58 -07:00
|
|
|
|
2011-08-07 16:52:49 +01:00
|
|
|
|
|
|
|
|
# check cxxabi stuff (which Mac OS X Lion breaks)
|
|
|
|
|
fragment = r"""
|
|
|
|
|
# include <cxxabi.h>
|
|
|
|
|
int main ()
|
|
|
|
|
{
|
|
|
|
|
const abi::__si_class_type_info *_typeinfo __attribute__((unused)) = NULL;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
"""
|
2011-09-08 16:13:40 +01:00
|
|
|
gcc_rtti_abi = conf.check_nonfatal(fragment=fragment, msg="Checking for internal GCC cxxabi",
|
|
|
|
|
okmsg="complete", errmsg='incomplete',
|
|
|
|
|
mandatory=False)
|
2011-08-07 16:52:49 +01:00
|
|
|
conf.env["GCC_RTTI_ABI_COMPLETE"] = str(bool(gcc_rtti_abi))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2008-07-08 10:43:58 -07:00
|
|
|
## Check for pygccxml
|
|
|
|
|
try:
|
|
|
|
|
conf.check_python_module('pygccxml')
|
|
|
|
|
except Configure.ConfigurationError:
|
2008-09-05 18:16:29 +01:00
|
|
|
conf.report_optional_feature("pygccxml", "Python API Scanning Support", False,
|
|
|
|
|
"Missing 'pygccxml' Python module")
|
2008-07-08 10:43:58 -07:00
|
|
|
return
|
|
|
|
|
|
2011-09-08 16:13:40 +01:00
|
|
|
out = subprocess.Popen([conf.env['PYTHON'][0], "-c",
|
2008-07-08 10:43:58 -07:00
|
|
|
"import pygccxml; print pygccxml.__version__"],
|
|
|
|
|
stdout=subprocess.PIPE).communicate()[0]
|
|
|
|
|
pygccxml_version_str = out.strip()
|
|
|
|
|
pygccxml_version = tuple([int(x) for x in pygccxml_version_str.split('.')])
|
2011-09-08 16:13:40 +01:00
|
|
|
conf.msg('Checking for pygccxml version', pygccxml_version_str)
|
2008-07-08 10:43:58 -07:00
|
|
|
if not (pygccxml_version >= REQUIRED_PYGCCXML_VERSION):
|
2008-12-29 16:54:53 +00:00
|
|
|
Logs.warn("pygccxml (found %s) is too old (need %s) => "
|
2008-07-08 10:43:58 -07:00
|
|
|
"automatic scanning of API definitions will not be possible" %
|
|
|
|
|
(pygccxml_version_str,
|
|
|
|
|
'.'.join([str(x) for x in REQUIRED_PYGCCXML_VERSION])))
|
2008-09-05 18:16:29 +01:00
|
|
|
conf.report_optional_feature("pygccxml", "Python API Scanning Support", False,
|
|
|
|
|
"pygccxml too old")
|
2008-07-08 10:43:58 -07:00
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Check gccxml version
|
|
|
|
|
gccxml = conf.find_program('gccxml', var='GCCXML')
|
|
|
|
|
if not gccxml:
|
2008-12-29 16:54:53 +00:00
|
|
|
Logs.warn("gccxml missing; automatic scanning of API definitions will not be possible")
|
2008-09-05 18:16:29 +01:00
|
|
|
conf.report_optional_feature("pygccxml", "Python API Scanning Support", False,
|
|
|
|
|
"gccxml missing")
|
2008-07-08 10:43:58 -07:00
|
|
|
return
|
|
|
|
|
|
|
|
|
|
gccxml_version_line = os.popen(gccxml + " --version").readline().strip()
|
|
|
|
|
m = re.match( "^GCC-XML version (\d\.\d(\.\d)?)$", gccxml_version_line)
|
|
|
|
|
gccxml_version = m.group(1)
|
|
|
|
|
gccxml_version_ok = ([int(s) for s in gccxml_version.split('.')] >= [0, 9])
|
2011-09-08 16:13:40 +01:00
|
|
|
conf.msg('Checking for gccxml version', gccxml_version)
|
2008-07-08 10:43:58 -07:00
|
|
|
if not gccxml_version_ok:
|
2008-12-29 16:54:53 +00:00
|
|
|
Logs.warn("gccxml too old, need version >= 0.9; automatic scanning of API definitions will not be possible")
|
2008-09-05 18:16:29 +01:00
|
|
|
conf.report_optional_feature("pygccxml", "Python API Scanning Support", False,
|
|
|
|
|
"gccxml too old")
|
2008-07-08 10:43:58 -07:00
|
|
|
return
|
2010-11-07 23:17:52 +00:00
|
|
|
|
2008-07-08 10:43:58 -07:00
|
|
|
## If we reached
|
|
|
|
|
conf.env['ENABLE_PYTHON_SCANNING'] = True
|
2008-09-05 18:16:29 +01:00
|
|
|
conf.report_optional_feature("pygccxml", "Python API Scanning Support", True, None)
|
2008-07-08 10:43:58 -07:00
|
|
|
|
2010-11-07 23:17:52 +00:00
|
|
|
# ---------------------
|
|
|
|
|
|
|
|
|
|
def get_headers_map(bld):
|
|
|
|
|
headers_map = {} # header => module
|
|
|
|
|
for ns3headers in bld.all_task_gen:
|
|
|
|
|
if type(ns3headers).__name__ == 'ns3header_taskgen': # XXX: find less hackish way to compare
|
2011-03-29 18:15:52 +01:00
|
|
|
if ns3headers.module.endswith('-test'):
|
|
|
|
|
continue
|
2010-11-07 23:17:52 +00:00
|
|
|
for h in ns3headers.to_list(ns3headers.source):
|
|
|
|
|
headers_map[os.path.basename(h)] = ns3headers.module
|
|
|
|
|
return headers_map
|
|
|
|
|
|
|
|
|
|
def get_module_path(bld, module):
|
|
|
|
|
for ns3headers in bld.all_task_gen:
|
|
|
|
|
if type(ns3headers).__name__ == 'ns3header_taskgen': # XXX: find less hackish way to compare
|
|
|
|
|
if ns3headers.module == module:
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
raise ValueError("Module %r not found" % module)
|
|
|
|
|
return ns3headers.path.abspath()
|
|
|
|
|
|
|
|
|
|
class apiscan_task(Task.TaskBase):
|
|
|
|
|
"""Uses gccxml to scan the file 'everything.h' and extract API definitions.
|
|
|
|
|
"""
|
2011-09-08 16:13:40 +01:00
|
|
|
after = 'gen_ns3_module_header ns3header'
|
2010-11-07 23:17:52 +00:00
|
|
|
before = 'cc cxx gchx'
|
|
|
|
|
color = "BLUE"
|
|
|
|
|
def __init__(self, curdirnode, env, bld, target, cflags, module):
|
|
|
|
|
self.bld = bld
|
|
|
|
|
super(apiscan_task, self).__init__(generator=self)
|
|
|
|
|
self.curdirnode = curdirnode
|
|
|
|
|
self.env = env
|
|
|
|
|
self.target = target
|
|
|
|
|
self.cflags = cflags
|
|
|
|
|
self.module = module
|
|
|
|
|
|
|
|
|
|
def display(self):
|
|
|
|
|
return 'api-scan-%s\n' % (self.target,)
|
|
|
|
|
|
|
|
|
|
def run(self):
|
|
|
|
|
top_builddir = self.curdirnode.find_dir('../..').abspath(self.env)
|
|
|
|
|
module_path = get_module_path(self.bld, self.module)
|
|
|
|
|
headers_map = get_headers_map(self.bld)
|
2011-03-20 17:56:06 +00:00
|
|
|
scan_header = os.path.join(top_builddir, "ns3", "%s-module.h" % self.module)
|
|
|
|
|
|
|
|
|
|
if not os.path.exists(scan_header):
|
|
|
|
|
Logs.error("Cannot apiscan module %r: %s does not exist" % (self.module, scan_header))
|
|
|
|
|
return 0
|
|
|
|
|
|
2010-11-07 23:17:52 +00:00
|
|
|
argv = [
|
|
|
|
|
self.env['PYTHON'],
|
|
|
|
|
os.path.join(self.curdirnode.abspath(), 'ns3modulescan-modular.py'), # scanning script
|
|
|
|
|
top_builddir,
|
|
|
|
|
self.module,
|
|
|
|
|
repr(get_headers_map(self.bld)),
|
|
|
|
|
os.path.join(module_path, "bindings", 'modulegen__%s.py' % (self.target)), # output file
|
|
|
|
|
self.cflags,
|
|
|
|
|
]
|
|
|
|
|
scan = subprocess.Popen(argv, stdin=subprocess.PIPE)
|
|
|
|
|
retval = scan.wait()
|
|
|
|
|
return retval
|
|
|
|
|
|
2008-07-08 10:43:58 -07:00
|
|
|
|
2009-04-13 23:10:37 +01:00
|
|
|
def get_modules_and_headers(bld):
|
2008-07-08 10:43:58 -07:00
|
|
|
"""
|
|
|
|
|
Gets a dict of
|
|
|
|
|
module_name => ([module_dep1, module_dep2, ...], [module_header1, module_header2, ...])
|
|
|
|
|
tuples, one for each module.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
retval = {}
|
2009-04-13 23:10:37 +01:00
|
|
|
for module in bld.all_task_gen:
|
2008-07-08 10:43:58 -07:00
|
|
|
if not module.name.startswith('ns3-'):
|
|
|
|
|
continue
|
2011-03-29 18:15:52 +01:00
|
|
|
if module.name.endswith('-test'):
|
|
|
|
|
continue
|
2008-07-08 10:43:58 -07:00
|
|
|
module_name = module.name[4:] # strip the ns3- prefix
|
|
|
|
|
## find the headers object for this module
|
|
|
|
|
headers = []
|
2009-04-13 23:10:37 +01:00
|
|
|
for ns3headers in bld.all_task_gen:
|
2008-07-08 10:43:58 -07:00
|
|
|
if type(ns3headers).__name__ != 'ns3header_taskgen': # XXX: find less hackish way to compare
|
|
|
|
|
continue
|
|
|
|
|
if ns3headers.module != module_name:
|
|
|
|
|
continue
|
|
|
|
|
for source in ns3headers.to_list(ns3headers.source):
|
2011-01-31 19:03:19 +00:00
|
|
|
headers.append(os.path.basename(source))
|
2008-07-08 10:43:58 -07:00
|
|
|
retval[module_name] = (list(module.module_deps), headers)
|
|
|
|
|
return retval
|
|
|
|
|
|
|
|
|
|
|
2008-08-18 23:04:49 +01:00
|
|
|
|
2009-09-22 16:13:42 +01:00
|
|
|
|
|
|
|
|
class python_scan_task_collector(Task.TaskBase):
|
|
|
|
|
"""Tasks that waits for the python-scan-* tasks to complete and then signals WAF to exit
|
|
|
|
|
"""
|
2011-09-08 16:13:40 +01:00
|
|
|
after = 'apiscan'
|
2009-09-22 16:13:42 +01:00
|
|
|
before = 'cc cxx'
|
|
|
|
|
color = "BLUE"
|
|
|
|
|
def __init__(self, curdirnode, env, bld):
|
|
|
|
|
self.bld = bld
|
|
|
|
|
super(python_scan_task_collector, self).__init__(generator=self)
|
|
|
|
|
self.curdirnode = curdirnode
|
|
|
|
|
self.env = env
|
|
|
|
|
|
|
|
|
|
def display(self):
|
|
|
|
|
return 'python-scan-collector\n'
|
|
|
|
|
|
|
|
|
|
def run(self):
|
2008-12-29 15:48:34 +00:00
|
|
|
# signal stop (we generated files into the source dir and WAF
|
|
|
|
|
# can't cope with it, so we have to force the user to restart
|
|
|
|
|
# WAF)
|
2009-04-13 23:10:37 +01:00
|
|
|
self.bld.generator.stop = 1
|
2008-12-29 15:48:34 +00:00
|
|
|
return 0
|
|
|
|
|
|
2008-08-18 23:04:49 +01:00
|
|
|
|
2011-03-13 16:03:33 +00:00
|
|
|
|
2011-03-28 15:31:13 +01:00
|
|
|
class gen_ns3_compat_pymod_task(Task.Task):
|
2011-03-13 16:03:33 +00:00
|
|
|
"""Generates a 'ns3.py' compatibility module."""
|
|
|
|
|
before = 'cc cxx gchx'
|
|
|
|
|
color = 'BLUE'
|
|
|
|
|
|
|
|
|
|
def run(self):
|
2011-03-28 15:31:13 +01:00
|
|
|
assert len(self.outputs) == 1
|
|
|
|
|
outfile = file(self.outputs[0].abspath(self.env), "w")
|
2011-03-13 16:03:33 +00:00
|
|
|
print >> outfile, "import warnings"
|
|
|
|
|
print >> outfile, 'warnings.warn("the ns3 module is a compatibility layer '\
|
|
|
|
|
'and should not be used in newly written code", DeprecationWarning, stacklevel=2)'
|
|
|
|
|
print >> outfile
|
|
|
|
|
for module in self.bld.env['PYTHON_MODULES_BUILT']:
|
2011-03-13 18:38:59 +00:00
|
|
|
print >> outfile, "from ns.%s import *" % (module.replace('-', '_'))
|
2011-03-13 16:03:33 +00:00
|
|
|
outfile.close()
|
|
|
|
|
return 0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2008-07-08 10:43:58 -07:00
|
|
|
def build(bld):
|
2008-12-29 13:28:54 +00:00
|
|
|
if Options.options.python_disable:
|
2008-07-08 10:43:58 -07:00
|
|
|
return
|
|
|
|
|
|
2008-12-29 13:28:54 +00:00
|
|
|
env = bld.env
|
|
|
|
|
curdir = bld.path.abspath()
|
2008-09-03 17:42:28 +01:00
|
|
|
|
2008-11-19 17:32:37 +00:00
|
|
|
set_pybindgen_pythonpath(env)
|
|
|
|
|
|
2011-03-28 14:56:08 +01:00
|
|
|
bld.new_task_gen(features='copy',
|
|
|
|
|
source="ns__init__.py",
|
|
|
|
|
target='ns/__init__.py')
|
2011-07-05 19:16:47 +01:00
|
|
|
bld.install_as('${PYTHONDIR}/ns/__init__.py', 'ns__init__.py')
|
2010-11-07 23:17:52 +00:00
|
|
|
|
|
|
|
|
if Options.options.apiscan:
|
|
|
|
|
if not env['ENABLE_PYTHON_SCANNING']:
|
|
|
|
|
raise Utils.WafError("Cannot re-scan python bindings: (py)gccxml not available")
|
|
|
|
|
scan_targets = []
|
|
|
|
|
if sys.platform == 'cygwin':
|
|
|
|
|
scan_targets.append(('gcc_cygwin', ''))
|
|
|
|
|
else:
|
|
|
|
|
import struct
|
|
|
|
|
if struct.calcsize('I') == 4 and struct.calcsize('L') == 8 and struct.calcsize('P') == 8:
|
|
|
|
|
scan_targets.extend([('gcc_ILP32', '-m32'), ('gcc_LP64', '-m64')])
|
|
|
|
|
elif struct.calcsize('I') == 4 and struct.calcsize('L') == 4 and struct.calcsize('P') == 4:
|
|
|
|
|
scan_targets.append(('gcc_ILP32', ''))
|
|
|
|
|
else:
|
|
|
|
|
raise Utils.WafError("Cannot scan python bindings for unsupported data model")
|
2011-03-21 18:16:41 +00:00
|
|
|
|
|
|
|
|
test_module_path = bld.path.find_dir("../../src/test")
|
2011-03-20 15:41:43 +00:00
|
|
|
if Options.options.apiscan == 'all':
|
2011-03-21 18:16:41 +00:00
|
|
|
scan_modules = []
|
|
|
|
|
for mod in bld.all_task_gen:
|
|
|
|
|
if not mod.name.startswith('ns3-'):
|
|
|
|
|
continue
|
|
|
|
|
if mod.path.is_child_of(test_module_path):
|
|
|
|
|
continue
|
2011-03-21 18:53:10 +00:00
|
|
|
if mod.name.endswith('-test'):
|
|
|
|
|
continue
|
2011-03-22 15:56:41 +00:00
|
|
|
bindings_enabled = (mod.name in env.MODULAR_BINDINGS_MODULES)
|
|
|
|
|
#print mod.name, bindings_enabled
|
|
|
|
|
if bindings_enabled:
|
|
|
|
|
scan_modules.append(mod.name.split('ns3-')[1])
|
2011-03-20 15:41:43 +00:00
|
|
|
else:
|
|
|
|
|
scan_modules = Options.options.apiscan.split(',')
|
|
|
|
|
print "Modules to scan: ", scan_modules
|
2010-11-07 23:17:52 +00:00
|
|
|
for target, cflags in scan_targets:
|
2011-03-20 15:41:43 +00:00
|
|
|
for module in scan_modules:
|
2010-11-07 23:17:52 +00:00
|
|
|
apiscan_task(bld.path, env, bld, target, cflags, module)
|
|
|
|
|
python_scan_task_collector(bld.path, env, bld)
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
2011-09-01 17:28:10 +01:00
|
|
|
if env['ENABLE_PYTHON_BINDINGS']:
|
2011-09-08 16:13:40 +01:00
|
|
|
task = gen_ns3_compat_pymod_task(env=env)
|
2011-03-28 15:31:13 +01:00
|
|
|
task.set_outputs(bld.path.find_or_declare("ns3.py"))
|
|
|
|
|
task.dep_vars = ['PYTHON_MODULES_BUILT']
|
|
|
|
|
|
2011-08-18 16:53:15 +01:00
|
|
|
# note: the actual build commands for the python bindings are in
|
|
|
|
|
# src/wscript, not here.
|
|
|
|
|
|