4 import os |
4 import os |
5 import subprocess |
5 import subprocess |
6 import shutil |
6 import shutil |
7 import sys |
7 import sys |
8 |
8 |
9 import Task |
9 from waflib import Task, Options, Configure, TaskGen, Logs, Build, Utils, Errors |
10 import Options |
|
11 import Configure |
|
12 import TaskGen |
|
13 import Logs |
|
14 import Build |
|
15 import Utils |
|
16 |
|
17 from waflib.Errors import WafError |
10 from waflib.Errors import WafError |
|
11 |
|
12 feature = TaskGen.feature |
|
13 after = TaskGen.after |
18 |
14 |
19 ## https://launchpad.net/pybindgen/ |
15 ## https://launchpad.net/pybindgen/ |
20 REQUIRED_PYBINDGEN_VERSION = (0, 15, 0, 809) |
16 REQUIRED_PYBINDGEN_VERSION = (0, 15, 0, 809) |
21 REQUIRED_PYGCCXML_VERSION = (0, 9, 5) |
17 REQUIRED_PYGCCXML_VERSION = (0, 9, 5) |
22 |
18 |
23 |
19 |
24 from TaskGen import feature, after |
|
25 import Task |
|
26 |
|
27 |
|
28 |
20 |
29 def add_to_python_path(path): |
21 def add_to_python_path(path): |
30 if os.environ.get('PYTHONPATH', ''): |
22 if os.environ.get('PYTHONPATH', ''): |
31 os.environ['PYTHONPATH'] = path + os.pathsep + os.environ.get('PYTHONPATH') |
23 os.environ['PYTHONPATH'] = path + os.pathsep + os.environ.get('PYTHONPATH') |
32 else: |
24 else: |
36 if env['WITH_PYBINDGEN']: |
28 if env['WITH_PYBINDGEN']: |
37 add_to_python_path(env['WITH_PYBINDGEN']) |
29 add_to_python_path(env['WITH_PYBINDGEN']) |
38 |
30 |
39 |
31 |
40 def options(opt): |
32 def options(opt): |
41 opt.tool_options('python') |
33 opt.load('python') |
42 opt.add_option('--disable-python', |
34 opt.add_option('--disable-python', |
43 help=("Don't build Python bindings."), |
35 help=("Don't build Python bindings."), |
44 action="store_true", default=False, |
36 action="store_true", default=False, |
45 dest='python_disable') |
37 dest='python_disable') |
46 opt.add_option('--apiscan', |
38 opt.add_option('--apiscan', |
74 enabled_modules.sort() |
66 enabled_modules.sort() |
75 available_modules = list(conf.env['NS3_MODULES']) |
67 available_modules = list(conf.env['NS3_MODULES']) |
76 available_modules.sort() |
68 available_modules.sort() |
77 all_modules_enabled = (enabled_modules == available_modules) |
69 all_modules_enabled = (enabled_modules == available_modules) |
78 |
70 |
79 conf.check_tool('misc', tooldir=['waf-tools']) |
71 conf.load('misc', tooldir=['waf-tools']) |
80 |
72 |
81 if sys.platform == 'cygwin': |
73 if sys.platform == 'cygwin': |
82 conf.report_optional_feature("python", "Python Bindings", False, |
74 conf.report_optional_feature("python", "Python Bindings", False, |
83 "unsupported platform 'cygwin'") |
75 "unsupported platform 'cygwin'") |
84 Logs.warn("Python is not supported in CygWin environment. Try MingW instead.") |
76 Logs.warn("Python is not supported in CygWin environment. Try MingW instead.") |
89 |
81 |
90 if Options.options.with_python is not None: |
82 if Options.options.with_python is not None: |
91 conf.env.PYTHON = Options.options.with_python |
83 conf.env.PYTHON = Options.options.with_python |
92 |
84 |
93 try: |
85 try: |
94 conf.check_tool('python') |
86 conf.load('python') |
95 except Configure.ConfigurationError, ex: |
87 except Errors.ConfigurationError, ex: |
96 conf.report_optional_feature("python", "Python Bindings", False, |
88 conf.report_optional_feature("python", "Python Bindings", False, |
97 "The python interpreter was not found") |
89 "The python interpreter was not found") |
98 return |
90 return |
99 try: |
91 try: |
100 conf.check_python_version((2,3)) |
92 conf.check_python_version((2,3)) |
101 except Configure.ConfigurationError, ex: |
93 except Errors.ConfigurationError, ex: |
102 conf.report_optional_feature("python", "Python Bindings", False, |
94 conf.report_optional_feature("python", "Python Bindings", False, |
103 "The python found version is too low (2.3 required)") |
95 "The python found version is too low (2.3 required)") |
104 return |
96 return |
105 try: |
97 try: |
106 conf.check_python_headers() |
98 conf.check_python_headers() |
107 except Configure.ConfigurationError, ex: |
99 except Errors.ConfigurationError, ex: |
108 conf.report_optional_feature("python", "Python Bindings", False, |
100 conf.report_optional_feature("python", "Python Bindings", False, |
109 "Python library or headers missing") |
101 "Python library or headers missing") |
110 return |
102 return |
111 |
103 |
112 # stupid Mac OSX Python wants to build extensions as "universal |
104 # stupid Mac OSX Python wants to build extensions as "universal |
159 |
151 |
160 set_pybindgen_pythonpath(conf.env) |
152 set_pybindgen_pythonpath(conf.env) |
161 |
153 |
162 try: |
154 try: |
163 conf.check_python_module('pybindgen') |
155 conf.check_python_module('pybindgen') |
164 except Configure.ConfigurationError: |
156 except Errors.ConfigurationError: |
165 Logs.warn("pybindgen missing => no python bindings") |
157 Logs.warn("pybindgen missing => no python bindings") |
166 conf.report_optional_feature("python", "Python Bindings", False, |
158 conf.report_optional_feature("python", "Python Bindings", False, |
167 "PyBindGen missing") |
159 "PyBindGen missing") |
168 return |
160 return |
169 else: |
161 else: |
195 } |
187 } |
196 ''' % dict(type1=t1, type2=t2) |
188 ''' % dict(type1=t1, type2=t2) |
197 |
189 |
198 try: |
190 try: |
199 ret = conf.run_c_code(code=test_program, |
191 ret = conf.run_c_code(code=test_program, |
200 env=conf.env.copy(), compile_filename='test.cc', |
192 env=conf.env.derive(), compile_filename='test.cc', |
201 features='cxx cprogram', execute=False) |
193 features='cxx cprogram', execute=False) |
202 except Configure.ConfigurationError: |
194 except Errors.ConfigurationError: |
203 ret = 1 |
195 ret = 1 |
204 conf.msg('Checking for types %s and %s equivalence' % (t1, t2), (ret and 'no' or 'yes')) |
196 conf.msg('Checking for types %s and %s equivalence' % (t1, t2), (ret and 'no' or 'yes')) |
205 return not ret |
197 return not ret |
206 |
198 |
207 uint64_is_long = test("uint64_t", "unsigned long") |
199 uint64_is_long = test("uint64_t", "unsigned long") |
248 |
240 |
249 |
241 |
250 ## Check for pygccxml |
242 ## Check for pygccxml |
251 try: |
243 try: |
252 conf.check_python_module('pygccxml') |
244 conf.check_python_module('pygccxml') |
253 except Configure.ConfigurationError: |
245 except Errors.ConfigurationError: |
254 conf.report_optional_feature("pygccxml", "Python API Scanning Support", False, |
246 conf.report_optional_feature("pygccxml", "Python API Scanning Support", False, |
255 "Missing 'pygccxml' Python module") |
247 "Missing 'pygccxml' Python module") |
256 return |
248 return |
257 |
249 |
258 out = subprocess.Popen([conf.env['PYTHON'][0], "-c", |
250 out = subprocess.Popen([conf.env['PYTHON'][0], "-c", |
320 |
312 |
321 class apiscan_task(Task.TaskBase): |
313 class apiscan_task(Task.TaskBase): |
322 """Uses gccxml to scan the file 'everything.h' and extract API definitions. |
314 """Uses gccxml to scan the file 'everything.h' and extract API definitions. |
323 """ |
315 """ |
324 after = 'gen_ns3_module_header ns3header' |
316 after = 'gen_ns3_module_header ns3header' |
325 before = 'cc cxx command' |
317 before = 'cxx command' |
326 color = "BLUE" |
318 color = "BLUE" |
327 def __init__(self, curdirnode, env, bld, target, cflags, module): |
319 def __init__(self, curdirnode, env, bld, target, cflags, module): |
328 self.bld = bld |
320 self.bld = bld |
329 super(apiscan_task, self).__init__(generator=self) |
321 super(apiscan_task, self).__init__(generator=self) |
330 self.curdirnode = curdirnode |
322 self.curdirnode = curdirnode |
391 |
383 |
392 class python_scan_task_collector(Task.TaskBase): |
384 class python_scan_task_collector(Task.TaskBase): |
393 """Tasks that waits for the python-scan-* tasks to complete and then signals WAF to exit |
385 """Tasks that waits for the python-scan-* tasks to complete and then signals WAF to exit |
394 """ |
386 """ |
395 after = 'apiscan' |
387 after = 'apiscan' |
396 before = 'cc cxx' |
388 before = 'cxx' |
397 color = "BLUE" |
389 color = "BLUE" |
398 def __init__(self, curdirnode, env, bld): |
390 def __init__(self, curdirnode, env, bld): |
399 self.bld = bld |
391 self.bld = bld |
400 super(python_scan_task_collector, self).__init__(generator=self) |
392 super(python_scan_task_collector, self).__init__(generator=self) |
401 self.curdirnode = curdirnode |
393 self.curdirnode = curdirnode |
435 def build(bld): |
427 def build(bld): |
436 if Options.options.python_disable: |
428 if Options.options.python_disable: |
437 return |
429 return |
438 |
430 |
439 env = bld.env |
431 env = bld.env |
440 curdir = bld.path.abspath() |
|
441 |
|
442 set_pybindgen_pythonpath(env) |
432 set_pybindgen_pythonpath(env) |
443 |
433 |
444 if Options.options.apiscan: |
434 if Options.options.apiscan: |
445 if not env['ENABLE_PYTHON_SCANNING']: |
435 if not env['ENABLE_PYTHON_SCANNING']: |
446 raise WafError("Cannot re-scan python bindings: (py)gccxml not available") |
436 raise WafError("Cannot re-scan python bindings: (py)gccxml not available") |
487 task.dep_vars = ['PYTHON_MODULES_BUILT'] |
477 task.dep_vars = ['PYTHON_MODULES_BUILT'] |
488 task.bld = bld |
478 task.bld = bld |
489 grp = bld.get_group(bld.current_group) |
479 grp = bld.get_group(bld.current_group) |
490 grp.append(task) |
480 grp.append(task) |
491 |
481 |
492 bld.new_task_gen(features='copy', |
482 bld(features='copy', source="ns__init__.py", target='ns/__init__.py') |
493 source="ns__init__.py", |
|
494 target='ns/__init__.py') |
|
495 bld.install_as('${PYTHONARCHDIR}/ns/__init__.py', 'ns__init__.py') |
483 bld.install_as('${PYTHONARCHDIR}/ns/__init__.py', 'ns__init__.py') |
496 |
484 |
497 |
485 |
498 # note: the actual build commands for the python bindings are in |
486 # note: the actual build commands for the python bindings are in |
499 # src/wscript, not here. |
487 # src/wscript, not here. |