--- a/.hgignore Sat Aug 20 14:41:19 2011 -0400
+++ b/.hgignore Mon Oct 17 16:59:17 2011 -0400
@@ -14,7 +14,7 @@
^testpy-output
^doc/html
^doc/latex
-^\.lock-wscript
+^\.lock-wafbuild
^\.waf
^doc/introspected-doxygen\.h$
.*\.py[co]$
--- a/.hgtags Sat Aug 20 14:41:19 2011 -0400
+++ b/.hgtags Mon Oct 17 16:59:17 2011 -0400
@@ -59,3 +59,4 @@
e48ed3aabca6ad71c8c49e4604c0f83345eda6a8 ns-3.11-RC3
9843c12351cb5ceb9613c9db390d94073b713284 ns-3.11
19c9e2b33b4a53f200be80cd49810bdfecf76770 ns-3.12-RC1
+167fc2274f53d4d89fdd769e4a7683ad7b6b7157 ns-3.12
--- a/CHANGES.html Sat Aug 20 14:41:19 2011 -0400
+++ b/CHANGES.html Mon Oct 17 16:59:17 2011 -0400
@@ -44,6 +44,62 @@
us a note on ns-developers mailing list. </p>
<hr>
+<h1>Changes from ns-3.12 to ns-3.13</h1>
+
+<h2>Changes to build system:</h2>
+<ul>
+<li> The underlying version of waf used by ns-3 was upgraded to 1.6.7.
+This has a few changes for users and developers:
+<ul>
+<li> by default, "build" no longer has a subdirectory debug or optimized.
+To get different build directories for different build types, you can use
+the waf configure -o xxx option, e.g.:
+<pre>
+ ./waf configure -o shared
+ ./waf configure --enable-static -o static
+</pre>
+</li>
+<li> (for developers) the ns3headers taskgen needs to be created with a
+features parameter name:
+<pre>
+ - headers = bld.new_task_gen('ns3header')
+ + headers = bld.new_task_gen(features=['ns3header'])
+</pre>
+<li> no longer need to edit src/wscript to add a module, just create your
+module directory inside src and ns-3 will pick it up
+<li> In WAF 1.6, adding -Dxxx options is done via the DEFINES env. var.
+instead of CXXDEFINES
+<li> waf env values are always lists now, e.g. env['PYTHON'] returns
+['/usr/bin/python'], so you may need to add [0] to the value in some places
+</ul>
+</ul>
+
+<h2>New API:</h2>
+<ul>
+</ul>
+
+<h2>Changes to existing API:</h2>
+<ul>
+<li> The WifiPhyStandard enumerators for specifying half- and quarter-channel
+width standards has had a change in capitalization:
+<ul>
+<li> WIFI_PHY_STANDARD_80211_10Mhz was changed to WIFI_PHY_STANDARD_80211_10MHZ
+<li> WIFI_PHY_STANDARD_80211_5Mhz was changed to WIFI_PHY_STANDARD_80211_5MHZ
+</ul>
+<li> In the SpectrumPhy base class, the methods to get/set the
+ MobilityModel and the NetDevice were previously working with
+ opaque Ptr<Object>. Now all these methods have been
+ changed so that they work with Ptr<NetDevice>
+ and Ptr<MobilityModel> as appropriate. See <A href="https://www.nsnam.org/bugzilla/show_bug.cgi?id=1271">Bug 1271</A> on
+ bugzilla for the motivation.
+</li>
+</ul>
+
+<h2>Changed behavior:</h2>
+<ul>
+</ul>
+
+<hr>
<h1>Changes from ns-3.11 to ns-3.12</h1>
<h2>Changes to build system:</h2>
@@ -70,6 +126,7 @@
<h2>Changed behavior:</h2>
<ul>
+<li> IPv4 fragmentation is now supported.
</ul>
<hr>
--- a/RELEASE_NOTES Sat Aug 20 14:41:19 2011 -0400
+++ b/RELEASE_NOTES Mon Oct 17 16:59:17 2011 -0400
@@ -9,31 +9,60 @@
Consult the file CHANGES.html for more detailed information about changed
API and behavior across ns-3 releases.
-Release 3.12
-===========
+Release 3.13
+==============
Availability
------------
This release is not yet available.
+Bugs fixed
+----------
+
Supported platforms
-------------------
-ns-3.11 has been tested on the following platforms. Not all features are
+
+New user-visible features
+-------------------------
+
+Known issues
+------------
+In general, known issues are tracked on the project tracker available
+at http://www.nsnam.org/bugzilla/
+
+Release 3.12.1
+==============
+
+Availability
+------------
+This release is available from:
+http://www.nsnam.org/release/ns-allinone-3.12.1.tar.bz2
+
+Bugs fixed
+----------
+This release fixes PyViz visualizer's python bindings; otherwise, it
+is the same as the ns-3.12 release.
+
+Release 3.12
+===========
+
+Availability
+------------
+This release is available from:
+http://www.nsnam.org/release/ns-allinone-3.12.tar.bz2
+
+Supported platforms
+-------------------
+ns-3.12 has been tested on the following platforms. Not all features are
available on all platforms; check the Installation page on the project wiki.
-- Linux x86_64 Ubuntu 11.04
- - g++-4.5.2
-- Linux i686 Ubuntu 11.04
- - g++-4.5.2, g++-4.4.5
-- Linux x86_64 Fedora Core 15
- - g++-4.6.0
-- Linux x86_64 Fedora Core 14
- - g++-4.5.3, g++-4.4.6, g++-4.3.4
-- Linux x86_64 Fedora Core 10
- - g++-3.4.6, 4.0.4, 4.1.2, 4.2.4, 4.3.2, 4.4.0
-- OS X Snow Leopard
- - g++-4.2.1
-- OS X Lion
+- Fedora Core 15 (32/64 bit) with g++-4.6.0
+- Ubuntu 11.04 (32/64 bit) with g++-4.5.2
+- OS X Lion with g++-4.2.1
+- Fedora Core 14 (64 bit) with g++-4.3.4, g++-4.5.3, g++-4.4.6
+- Fedora Core 12 (64 bit) with g++-4.4.4
+- OS X Snow Leopard with g++-4.2.1
+- Ubuntu 10.04.3 LTS (64 bit) with g++-4.4.3, g++-3.4.6
New user-visible features
-------------------------
@@ -49,7 +78,7 @@
container objects in addition to vector containers. The ObjectMap
and related classes are patterned after ObjectVector.
-- Support to IPv4 fragmentation has been added.
+- Support for IPv4 fragmentation has been added.
- Significant performance improvement for AODV in dense mobile scenarios
due to a fixed bug in RERR processing.
@@ -62,7 +91,7 @@
Bugs fixed
----------
- - bug 845 - fix ConfigStore output for changing default values
+ - bug 845 - fix ConfigStore output for changing default values
- bug 1010 - Uan model Sleep patch
- bug 1033 - Mesh airtime-metric fixed
- bug 1043 - lte-spectrum-value-helper.cc file swapped uplink/downlink freq.
@@ -72,7 +101,7 @@
- bug 1100 - IPv6 fragmentation enhancements
- bug 1102 - IPv4 header fragment offset field not set correctly
- bug 1123 - class MinMaxAvgTotalCalculator does not implement all methods
- - bug 1134: Fix LiIonEnergySource attribute spelling for InitialCellVoltage
+ - bug 1134 - Fix LiIonEnergySource attribute spelling for InitialCellVoltage
- bug 1139 - Broadcast packets issue in uan cw mac
- bug 1141 - MeshWifiInterfaceMac adds supported modes to wrong remote station
- bug 1163 - Ipv4EndPointDemux::AllocateEphemeralPort forget to increment port
@@ -87,7 +116,7 @@
- bug 1209 - ns-3-click fails to build on Fedora 15 when tests are enabled
- bug 1220 - FdReader always stops with NS_FATAL_ERROR
- bug 1222 - Incomplete PointToPointNetDevice Python bindings
- - bug 1224 - Ns-3-allinone fails to compile on Lion
+ - bug 1224 - ns-3-allinone fails to compile on OS X Lion
- bug 1226 - Incomplete YansWifiChannel Python bindings
- bug 1234 - GetAttributeChecker is not defined anymore but still used
- bug 1239 - Add assertion that reference count never overflows
@@ -105,7 +134,7 @@
Availability
------------
This release is available from:
-http://www.nsnam.org/releases/ns-allinone-3.11.tar.bz2
+http://www.nsnam.org/release/ns-allinone-3.11.tar.bz2
Supported platforms
-------------------
@@ -246,7 +275,7 @@
Availability
------------
This release is available from:
-http://www.nsnam.org/releases/ns-allinone-3.10.tar.bz2
+http://www.nsnam.org/release/ns-allinone-3.10.tar.bz2
Supported platforms
-------------------
@@ -411,7 +440,7 @@
Availability
------------
This release is immediately available from:
-http://www.nsnam.org/releases/ns-allinone-3.9.tar.bz2
+http://www.nsnam.org/release/ns-allinone-3.9.tar.bz2
Supported platforms
-------------------
@@ -571,7 +600,7 @@
Availability
------------
This release is immediately available from:
-http://www.nsnam.org/releases/ns-allinone-3.8.tar.bz2
+http://www.nsnam.org/release/ns-allinone-3.8.tar.bz2
Supported platforms
-------------------
@@ -711,7 +740,7 @@
Availability
------------
This release is immediately available from:
-http://www.nsnam.org/releases/ns-allinone-3.7.tar.bz2
+http://www.nsnam.org/release/ns-allinone-3.7.tar.bz2
Supported platforms
-------------------
@@ -835,7 +864,7 @@
Availability
------------
This release is immediately available from:
-http://www.nsnam.org/releases/ns-allinone-3.6.tar.bz2
+http://www.nsnam.org/release/ns-allinone-3.6.tar.bz2
Supported platforms
-------------------
@@ -911,7 +940,7 @@
Availability
------------
This release is immediately available from:
-http://www.nsnam.org/releases/ns-allinone-3.5.tar.bz2
+http://www.nsnam.org/release/ns-allinone-3.5.tar.bz2
Supported platforms
-------------------
@@ -970,7 +999,7 @@
Availability
------------
This release is immediately available from:
-http://www.nsnam.org/releases/ns-allinone-3.4.tar.bz2
+http://www.nsnam.org/release/ns-allinone-3.4.tar.bz2
Supported platforms
-------------------
@@ -1034,7 +1063,7 @@
Availability
------------
This release is immediately available from:
-http://www.nsnam.org/releases/ns-3.3.tar.bz2
+http://www.nsnam.org/release/ns-3.3.tar.bz2
Supported platforms
-------------------
@@ -1101,7 +1130,7 @@
Availability
------------
This release is immediately available from:
-http://www.nsnam.org/releases/ns-3.2.tar.bz2
+http://www.nsnam.org/release/ns-3.2.tar.bz2
Supported platforms
-------------------
@@ -1172,7 +1201,7 @@
-----------------------------
This release is immediately available from:
-http://www.nsnam.org/releases/ns-3.1.tar.bz2
+http://www.nsnam.org/release/ns-3.1.tar.bz2
We dedicate this initial ns-3 release to our late contributor and friend,
Federico Maguolo.
--- a/bindings/python/wscript Sat Aug 20 14:41:19 2011 -0400
+++ b/bindings/python/wscript Mon Oct 17 16:59:17 2011 -0400
@@ -2,7 +2,7 @@
import types
import re
import os
-import pproc as subprocess
+import subprocess
import shutil
import sys
@@ -14,15 +14,15 @@
import Build
import Utils
+from waflib.Errors import WafError
+
## https://launchpad.net/pybindgen/
REQUIRED_PYBINDGEN_VERSION = (0, 15, 0, 795)
REQUIRED_PYGCCXML_VERSION = (0, 9, 5)
-
from TaskGen import feature, after
-import Task, ccroot
-from python import _get_python_variables # this comes from wafadmin/Tools/python.py
+import Task
@@ -37,18 +37,14 @@
add_to_python_path(env['WITH_PYBINDGEN'])
-def set_options(opt):
- opt.tool_options('python')
+def options(opt):
+ opt.tool_options('python', ["waf-tools"])
opt.add_option('--disable-python',
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')
opt.add_option('--apiscan',
- help=("EXPERIMENTAL: Rescan the API for the indicated module(s), for Python bindings. "
+ help=("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."),
default=None, dest='apiscan', metavar="MODULE[,MODULE...]")
@@ -56,6 +52,9 @@
help=('Path to an existing pybindgen source tree to use.'),
default=None,
dest='with_pybindgen', type="string")
+ opt.add_option('--with-python',
+ help=('Path to the Python interpreter to use.'),
+ default=None, dest='with_python', type="string")
def configure(conf):
@@ -64,6 +63,12 @@
conf.report_optional_feature("python", "Python Bindings", False,
"disabled by user request")
return
+ # 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
enabled_modules = list(conf.env['NS3_ENABLED_MODULES'])
enabled_modules.sort()
@@ -71,7 +76,7 @@
available_modules.sort()
all_modules_enabled = (enabled_modules == available_modules)
- conf.check_tool('misc')
+ conf.check_tool('misc', tooldir=['waf-tools'])
if sys.platform == 'cygwin':
conf.report_optional_feature("python", "Python Bindings", False,
@@ -79,27 +84,35 @@
Logs.warn("Python is not supported in CygWin environment. Try MingW instead.")
return
+
## Check for Python
+
+ if Options.options.with_python is not None:
+ conf.env.PYTHON = Options.options.with_python
+
try:
- conf.check_tool('python')
+ conf.check_tool('python', ["waf-tools"])
conf.check_python_version((2,3))
conf.check_python_headers()
except Configure.ConfigurationError, ex:
conf.report_optional_feature("python", "Python Bindings", False, str(ex))
return
-
- # 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
-
+ # stupid Mac OSX Python wants to build extensions as "universal
+ # binaries", i386, x86_64, and ppc, but this way the type
+ # __uint128_t is not available. We need to disable the multiarch
+ # crap by removing the -arch parameters.
+ for flags_var in ["CFLAGS_PYEXT", "CFLAGS_PYEMBED", "CXXFLAGS_PYEMBED",
+ "CXXFLAGS_PYEXT", "LINKFLAGS_PYEMBED", "LINKFLAGS_PYEXT"]:
+ flags = conf.env[flags_var]
+ i = 0
+ while i < len(flags):
+ if flags[i] == '-arch':
+ del flags[i]
+ del flags[i]
+ continue
+ i += 1
+ conf.env[flags_var] = flags
# -fvisibility=hidden optimization
if (conf.env['CXX_NAME'] == 'gcc' and [int(x) for x in conf.env['CC_VERSION']] >= [4,0,0]
@@ -110,7 +123,7 @@
# Check for the location of pybindgen
if Options.options.with_pybindgen is not None:
if os.path.isdir(Options.options.with_pybindgen):
- conf.check_message("pybindgen location", '', True, ("%s (given)" % Options.options.with_pybindgen))
+ conf.msg("Checking for pybindgen location", ("%s (given)" % Options.options.with_pybindgen))
conf.env['WITH_PYBINDGEN'] = os.path.abspath(Options.options.with_pybindgen)
else:
# ns-3-dev uses ../pybindgen, while ns-3 releases use ../REQUIRED_PYBINDGEN_VERSION
@@ -118,15 +131,15 @@
pybindgen_release_str = "pybindgen-" + '.'.join([str(x) for x in REQUIRED_PYBINDGEN_VERSION])
pybindgen_release_dir = os.path.join('..', pybindgen_release_str)
if os.path.isdir(pybindgen_dir):
- conf.check_message("pybindgen location", '', True, ("%s (guessed)" % pybindgen_dir))
+ conf.msg("Checking for pybindgen location", ("%s (guessed)" % pybindgen_dir))
conf.env['WITH_PYBINDGEN'] = os.path.abspath(pybindgen_dir)
elif os.path.isdir(pybindgen_release_dir):
- conf.check_message("pybindgen location", '', True, ("%s (guessed)" % pybindgen_release_dir))
+ conf.msg("Checking for pybindgen location", ("%s (guessed)" % pybindgen_release_dir))
conf.env['WITH_PYBINDGEN'] = os.path.abspath(pybindgen_release_dir)
del pybindgen_dir
del pybindgen_release_dir
if not conf.env['WITH_PYBINDGEN']:
- conf.check_message("pybindgen location", '', False)
+ conf.msg("Checking for pybindgen location", False)
# Check for pybindgen
@@ -140,15 +153,13 @@
"PyBindGen missing")
return
else:
- out = subprocess.Popen([conf.env['PYTHON'], "-c",
+ out = subprocess.Popen([conf.env['PYTHON'][0], "-c",
"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('.')])
- conf.check_message('pybindgen', 'version',
- (pybindgen_version == REQUIRED_PYBINDGEN_VERSION),
- pybindgen_version_str)
+ conf.msg('Checking for pybindgen version', pybindgen_version_str)
if not (pybindgen_version == REQUIRED_PYBINDGEN_VERSION):
Logs.warn("pybindgen (found %s), (need %s)" %
(pybindgen_version_str,
@@ -173,10 +184,10 @@
try:
ret = conf.run_c_code(code=test_program,
env=conf.env.copy(), compile_filename='test.cc',
- compile_mode='cxx',type='cprogram', execute=False)
+ features='cxx cprogram', execute=False)
except Configure.ConfigurationError:
ret = 1
- conf.check_message_custom('types %s and %s' % (t1, t2), 'equivalency', (ret and 'no' or 'yes'))
+ conf.msg('Checking for types %s and %s equivalence' % (t1, t2), (ret and 'no' or 'yes'))
return not ret
uint64_is_long = test("uint64_t", "unsigned long")
@@ -193,7 +204,7 @@
else:
msg = conf.env['PYTHON_BINDINGS_APIDEFS']
- conf.check_message_custom('the apidefs that can be used for Python bindings', '', msg)
+ conf.msg('Checking for the apidefs that can be used for Python bindings', msg)
if conf.env['PYTHON_BINDINGS_APIDEFS'] is None:
conf.report_optional_feature("python", "Python Bindings", False,
@@ -215,9 +226,9 @@
return 0;
}
"""
- gcc_rtti_abi = conf.check(fragment=fragment, msg="Checking for internal GCC cxxabi",
- okmsg="complete", errmsg='incomplete',
- mandatory=False)
+ gcc_rtti_abi = conf.check_nonfatal(fragment=fragment, msg="Checking for internal GCC cxxabi",
+ okmsg="complete", errmsg='incomplete',
+ mandatory=False)
conf.env["GCC_RTTI_ABI_COMPLETE"] = str(bool(gcc_rtti_abi))
@@ -230,14 +241,12 @@
"Missing 'pygccxml' Python module")
return
- out = subprocess.Popen([conf.env['PYTHON'], "-c",
+ out = subprocess.Popen([conf.env['PYTHON'][0], "-c",
"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('.')])
- conf.check_message('pygccxml', 'version',
- (pygccxml_version >= REQUIRED_PYGCCXML_VERSION),
- pygccxml_version_str)
+ conf.msg('Checking for pygccxml version', pygccxml_version_str)
if not (pygccxml_version >= REQUIRED_PYGCCXML_VERSION):
Logs.warn("pygccxml (found %s) is too old (need %s) => "
"automatic scanning of API definitions will not be possible" %
@@ -249,7 +258,10 @@
## Check gccxml version
- gccxml = conf.find_program('gccxml', var='GCCXML')
+ try:
+ gccxml = conf.find_program('gccxml', var='GCCXML')
+ except WafError:
+ gccxml = None
if not gccxml:
Logs.warn("gccxml missing; automatic scanning of API definitions will not be possible")
conf.report_optional_feature("pygccxml", "Python API Scanning Support", False,
@@ -260,7 +272,7 @@
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])
- conf.check_message('gccxml', 'version', True, gccxml_version)
+ conf.msg('Checking for gccxml version', gccxml_version)
if not gccxml_version_ok:
Logs.warn("gccxml too old, need version >= 0.9; automatic scanning of API definitions will not be possible")
conf.report_optional_feature("pygccxml", "Python API Scanning Support", False,
@@ -276,19 +288,18 @@
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
+ if 'ns3header' in getattr(ns3headers, "features", []):
if ns3headers.module.endswith('-test'):
continue
- for h in ns3headers.to_list(ns3headers.source):
+ for h in ns3headers.to_list(ns3headers.headers):
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 'ns3header' in getattr(ns3headers, "features", []):
if ns3headers.module == module:
break
-
else:
raise ValueError("Module %r not found" % module)
return ns3headers.path.abspath()
@@ -296,8 +307,8 @@
class apiscan_task(Task.TaskBase):
"""Uses gccxml to scan the file 'everything.h' and extract API definitions.
"""
- after = 'gen_ns3_module_header_task ns3header_task'
- before = 'cc cxx gchx'
+ after = 'gen_ns3_module_header ns3header'
+ before = 'cc cxx command'
color = "BLUE"
def __init__(self, curdirnode, env, bld, target, cflags, module):
self.bld = bld
@@ -312,7 +323,7 @@
return 'api-scan-%s\n' % (self.target,)
def run(self):
- top_builddir = self.curdirnode.find_dir('../..').abspath(self.env)
+ top_builddir = self.bld.bldnode.abspath()
module_path = get_module_path(self.bld, self.module)
headers_map = get_headers_map(self.bld)
scan_header = os.path.join(top_builddir, "ns3", "%s-module.h" % self.module)
@@ -322,7 +333,7 @@
return 0
argv = [
- self.env['PYTHON'],
+ self.env['PYTHON'][0],
os.path.join(self.curdirnode.abspath(), 'ns3modulescan-modular.py'), # scanning script
top_builddir,
self.module,
@@ -352,58 +363,22 @@
## find the headers object for this module
headers = []
for ns3headers in bld.all_task_gen:
- if type(ns3headers).__name__ != 'ns3header_taskgen': # XXX: find less hackish way to compare
+ if 'ns3header' not in getattr(ns3headers, "features", []):
continue
if ns3headers.module != module_name:
continue
- for source in ns3headers.to_list(ns3headers.source):
+ for source in ns3headers.to_list(ns3headers.headers):
headers.append(os.path.basename(source))
retval[module_name] = (list(module.module_deps), headers)
return retval
-class python_scan_task(Task.TaskBase):
- """Uses gccxml to scan the file 'everything.h' and extract API definitions.
- """
- after = 'gen_everything_h_task'
- before = 'cc cxx gchx'
- color = "BLUE"
- def __init__(self, curdirnode, env, bld, target, cflags):
- self.bld = bld
- super(python_scan_task, self).__init__(generator=self)
- self.curdirnode = curdirnode
- self.env = env
- self.target = target
- self.cflags = cflags
-
- def display(self):
- return 'python-scan-%s\n' % (self.target,)
-
- def run(self):
- defsdir = os.path.join(self.curdirnode.abspath(), 'apidefs', self.target)
- try:
- os.mkdir(defsdir)
- except OSError:
- pass
- argv = [
- self.env['PYTHON'],
- os.path.join(self.curdirnode.abspath(), 'ns3modulescan.py'), # scanning script
- self.curdirnode.find_dir('../..').abspath(self.env), # include path (where the ns3 include dir is)
- self.curdirnode.find_or_declare('everything.h').abspath(self.env),
- os.path.join(defsdir, 'ns3modulegen_generated.py'), # output file
- self.cflags,
- ]
- scan = subprocess.Popen(argv, stdin=subprocess.PIPE)
- print >> scan.stdin, repr(get_modules_and_headers(self.bld))
- scan.stdin.close()
- retval = scan.wait()
- return retval
class python_scan_task_collector(Task.TaskBase):
"""Tasks that waits for the python-scan-* tasks to complete and then signals WAF to exit
"""
- after = 'python_scan_task apiscan_task'
+ after = 'apiscan'
before = 'cc cxx'
color = "BLUE"
def __init__(self, curdirnode, env, bld):
@@ -419,19 +394,20 @@
# 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)
- self.bld.generator.stop = 1
+ self.bld.producer.stop = 1
+ self.bld.producer.free_task_pool()
return 0
class gen_ns3_compat_pymod_task(Task.Task):
"""Generates a 'ns3.py' compatibility module."""
- before = 'cc cxx gchx'
+ before = 'cc cxx'
color = 'BLUE'
def run(self):
assert len(self.outputs) == 1
- outfile = file(self.outputs[0].abspath(self.env), "w")
+ outfile = file(self.outputs[0].abspath(), "w")
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)'
@@ -452,14 +428,9 @@
set_pybindgen_pythonpath(env)
- bld.new_task_gen(features='copy',
- source="ns__init__.py",
- target='ns/__init__.py')
- bld.install_as('${PYTHONDIR}/ns/__init__.py', 'ns__init__.py')
-
if Options.options.apiscan:
if not env['ENABLE_PYTHON_SCANNING']:
- raise Utils.WafError("Cannot re-scan python bindings: (py)gccxml not available")
+ raise WafError("Cannot re-scan python bindings: (py)gccxml not available")
scan_targets = []
if sys.platform == 'cygwin':
scan_targets.append(('gcc_cygwin', ''))
@@ -470,7 +441,7 @@
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")
+ raise WafError("Cannot scan python bindings for unsupported data model")
test_module_path = bld.path.find_dir("../../src/test")
if Options.options.apiscan == 'all':
@@ -490,16 +461,26 @@
scan_modules = Options.options.apiscan.split(',')
print "Modules to scan: ", scan_modules
for target, cflags in scan_targets:
+ group = bld.get_group(bld.current_group)
for module in scan_modules:
- apiscan_task(bld.path, env, bld, target, cflags, module)
- python_scan_task_collector(bld.path, env, bld)
+ group.append(apiscan_task(bld.path, env, bld, target, cflags, module))
+ group.append(python_scan_task_collector(bld.path, env, bld))
return
- if env['ENABLE_PYTHON_BINDINGS'] and env['BINDINGS_TYPE'] in ('modular',):
- task = gen_ns3_compat_pymod_task(env)
+ if env['ENABLE_PYTHON_BINDINGS']:
+ task = gen_ns3_compat_pymod_task(env=env.derive())
task.set_outputs(bld.path.find_or_declare("ns3.py"))
task.dep_vars = ['PYTHON_MODULES_BUILT']
+ task.bld = bld
+ grp = bld.get_group(bld.current_group)
+ grp.append(task)
+
+ bld.new_task_gen(features='copy',
+ source="ns__init__.py",
+ target='ns/__init__.py')
+ bld.install_as('${PYTHONDIR}/ns/__init__.py', 'ns__init__.py')
+
# note: the actual build commands for the python bindings are in
# src/wscript, not here.
--- a/doc/manual/Makefile Sat Aug 20 14:41:19 2011 -0400
+++ b/doc/manual/Makefile Mon Oct 17 16:59:17 2011 -0400
@@ -11,7 +11,11 @@
# rescale pdf figures as necessary
$(FIGURES)/software-organization.pdf_width = 5in
-IMAGES_PNG = ${IMAGES_EPS:.eps=.png}
+IMAGES_PNG = \
+ $(FIGURES)/plot-2d.png \
+ $(FIGURES)/plot-2d-with-error-bars.png \
+ $(FIGURES)/plot-3d.png \
+ ${IMAGES_EPS:.eps=.png}
IMAGES_PDF = ${IMAGES_EPS:.eps=.pdf}
IMAGES = $(IMAGES_EPS) $(IMAGES_PNG) $(IMAGES_PDF)
Binary file doc/manual/figures/plot-2d-with-error-bars.png has changed
Binary file doc/manual/figures/plot-2d.png has changed
Binary file doc/manual/figures/plot-3d.png has changed
--- a/doc/manual/source/attributes.rst Sat Aug 20 14:41:19 2011 -0400
+++ b/doc/manual/source/attributes.rst Mon Oct 17 16:59:17 2011 -0400
@@ -278,7 +278,7 @@
+++++++++++++++++++++++++++++++++++++++++
Let's look at how a user script might access these values.
-This is based on the script found at ``src/core/examples/main-attribute-value.cc``,
+This is based on the script found at ``src/point-to-point/examples/main-attribute-value.cc``,
with some details stripped out.::
//
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/manual/source/gnuplot.rst Mon Oct 17 16:59:17 2011 -0400
@@ -0,0 +1,294 @@
+.. include:: replace.txt
+
+Making Plots using the Gnuplot Class
+------------------------------------
+
+There are 2 common methods to make a plot using |ns3| and gnuplot (http://www.gnuplot.info):
+
+#. Create a gnuplot control file using |ns3|'s Gnuplot class.
+#. Create a gnuplot data file using values generated by |ns3|.
+
+This section is about method 1, i.e. it is about how to make a plot using |ns3|'s Gnuplot class. If you are interested in method 2, see the "A Real Example" subsection under the "Tracing" section in the |ns3| `Tutorial <http://www.nsnam.org/tutorials.html>`_.
+
+Creating Plots Using the Gnuplot Class
+**************************************
+
+The following steps must be taken in order to create a plot using |ns3|'s Gnuplot class:
+
+#. Modify your code so that is uses the Gnuplot class and its functions.
+#. Run your code so that it creates a gnuplot control file.
+#. Call gnuplot with the name of the gnuplot control file.
+#. View the graphics file that was produced in your favorite graphics viewer.
+
+See the code from the example plots that are discussed below for details on step 1.
+
+An Example Program that Uses the Gnuplot Class
+**********************************************
+
+An example program that uses |ns3|'s Gnuplot class can be found here: ::
+
+ src/tools/examples/gnuplot-example.cc
+
+In order to run this example, do the following: ::
+
+ ./waf shell
+ cd build/debug/src/tools/examples
+ ./gnuplot-example
+
+This should produce the following gnuplot control files in the directory where the example is located: ::
+
+ plot-2d.plt
+ plot-2d-with-error-bars.plt
+ plot-3d.plt
+
+In order to process these gnuplot control files, do the following: ::
+
+ gnuplot plot-2d.plt
+ gnuplot plot-2d-with-error-bars.plt
+ gnuplot plot-3d.plt
+
+This should produce the following graphics files in the directory where the example is located: ::
+
+ plot-2d.png
+ plot-2d-with-error-bars.png
+ plot-3d.png
+
+You can view these graphics files in your favorite graphics viewer. If you have gimp installed on your machine, for example, you can do this: ::
+
+ gimp plot-2d.png
+ gimp plot-2d-with-error-bars.png
+ gimp plot-3d.png
+
+An Example 2-Dimensional Plot
+*****************************
+
+The following 2-Dimensional plot
+
+.. _plot-2d:
+
+.. figure:: figures/plot-2d.*
+
+was created using the following code from gnuplot-example.cc: ::
+
+ using namespace std;
+
+ string fileNameWithNoExtension = "plot-2d";
+ string graphicsFileName = fileNameWithNoExtension + ".png";
+ string plotFileName = fileNameWithNoExtension + ".plt";
+ string plotTitle = "2-D Plot";
+ string dataTitle = "2-D Data";
+
+ // Instantiate the plot and set its title.
+ Gnuplot plot (graphicsFileName);
+ plot.SetTitle (plotTitle);
+
+ // Make the graphics file, which the plot file will create when it
+ // is used with Gnuplot, be a PNG file.
+ plot.SetTerminal ("png");
+
+ // Set the labels for each axis.
+ plot.SetLegend ("X Values", "Y Values");
+
+ // Set the range for the x axis.
+ plot.AppendExtra ("set xrange [-6:+6]");
+
+ // Instantiate the dataset, set its title, and make the points be
+ // plotted along with connecting lines.
+ Gnuplot2dDataset dataset;
+ dataset.SetTitle (dataTitle);
+ dataset.SetStyle (Gnuplot2dDataset::LINES_POINTS);
+
+ double x;
+ double y;
+
+ // Create the 2-D dataset.
+ for (x = -5.0; x <= +5.0; x += 1.0)
+ {
+ // Calculate the 2-D curve
+ //
+ // 2
+ // y = x .
+ //
+ y = x * x;
+
+ // Add this point.
+ dataset.Add (x, y);
+ }
+
+ // Add the dataset to the plot.
+ plot.AddDataset (dataset);
+
+ // Open the plot file.
+ ofstream plotFile (plotFileName.c_str());
+
+ // Write the plot file.
+ plot.GenerateOutput (plotFile);
+
+ // Close the plot file.
+ plotFile.close ();
+
+An Example 2-Dimensional Plot with Error Bars
+*********************************************
+
+The following 2-Dimensional plot with error bars in the x and y directions
+
+.. _plot-2d-with-error-bars:
+
+.. figure:: figures/plot-2d-with-error-bars.*
+
+was created using the following code from gnuplot-example.cc: ::
+
+ using namespace std;
+
+ string fileNameWithNoExtension = "plot-2d-with-error-bars";
+ string graphicsFileName = fileNameWithNoExtension + ".png";
+ string plotFileName = fileNameWithNoExtension + ".plt";
+ string plotTitle = "2-D Plot With Error Bars";
+ string dataTitle = "2-D Data With Error Bars";
+
+ // Instantiate the plot and set its title.
+ Gnuplot plot (graphicsFileName);
+ plot.SetTitle (plotTitle);
+
+ // Make the graphics file, which the plot file will create when it
+ // is used with Gnuplot, be a PNG file.
+ plot.SetTerminal ("png");
+
+ // Set the labels for each axis.
+ plot.SetLegend ("X Values", "Y Values");
+
+ // Set the range for the x axis.
+ plot.AppendExtra ("set xrange [-6:+6]");
+
+ // Instantiate the dataset, set its title, and make the points be
+ // plotted with no connecting lines.
+ Gnuplot2dDataset dataset;
+ dataset.SetTitle (dataTitle);
+ dataset.SetStyle (Gnuplot2dDataset::POINTS);
+
+ // Make the dataset have error bars in both the x and y directions.
+ dataset.SetErrorBars (Gnuplot2dDataset::XY);
+
+ double x;
+ double xErrorDelta;
+ double y;
+ double yErrorDelta;
+
+ // Create the 2-D dataset.
+ for (x = -5.0; x <= +5.0; x += 1.0)
+ {
+ // Calculate the 2-D curve
+ //
+ // 2
+ // y = x .
+ //
+ y = x * x;
+
+ // Make the uncertainty in the x direction be constant and make
+ // the uncertainty in the y direction be a constant fraction of
+ // y's value.
+ xErrorDelta = 0.25;
+ yErrorDelta = 0.1 * y;
+
+ // Add this point with uncertainties in both the x and y
+ // direction.
+ dataset.Add (x, y, xErrorDelta, yErrorDelta);
+ }
+
+ // Add the dataset to the plot.
+ plot.AddDataset (dataset);
+
+ // Open the plot file.
+ ofstream plotFile (plotFileName.c_str());
+
+ // Write the plot file.
+ plot.GenerateOutput (plotFile);
+
+ // Close the plot file.
+ plotFile.close ();
+
+An Example 3-Dimensional Plot
+*****************************
+
+The following 3-Dimensional plot
+
+.. _plot-3d:
+
+.. figure:: figures/plot-3d.*
+
+was created using the following code from gnuplot-example.cc: ::
+
+ using namespace std;
+
+ string fileNameWithNoExtension = "plot-3d";
+ string graphicsFileName = fileNameWithNoExtension + ".png";
+ string plotFileName = fileNameWithNoExtension + ".plt";
+ string plotTitle = "3-D Plot";
+ string dataTitle = "3-D Data";
+
+ // Instantiate the plot and set its title.
+ Gnuplot plot (graphicsFileName);
+ plot.SetTitle (plotTitle);
+
+ // Make the graphics file, which the plot file will create when it
+ // is used with Gnuplot, be a PNG file.
+ plot.SetTerminal ("png");
+
+ // Rotate the plot 30 degrees around the x axis and then rotate the
+ // plot 120 degrees around the new z axis.
+ plot.AppendExtra ("set view 30, 120, 1.0, 1.0");
+
+ // Make the zero for the z-axis be in the x-axis and y-axis plane.
+ plot.AppendExtra ("set ticslevel 0");
+
+ // Set the labels for each axis.
+ plot.AppendExtra ("set xlabel 'X Values'");
+ plot.AppendExtra ("set ylabel 'Y Values'");
+ plot.AppendExtra ("set zlabel 'Z Values'");
+
+ // Set the ranges for the x and y axis.
+ plot.AppendExtra ("set xrange [-5:+5]");
+ plot.AppendExtra ("set yrange [-5:+5]");
+
+ // Instantiate the dataset, set its title, and make the points be
+ // connected by lines.
+ Gnuplot3dDataset dataset;
+ dataset.SetTitle (dataTitle);
+ dataset.SetStyle ("with lines");
+
+ double x;
+ double y;
+ double z;
+
+ // Create the 3-D dataset.
+ for (x = -5.0; x <= +5.0; x += 1.0)
+ {
+ for (y = -5.0; y <= +5.0; y += 1.0)
+ {
+ // Calculate the 3-D surface
+ //
+ // 2 2
+ // z = x * y .
+ //
+ z = x * x * y * y;
+
+ // Add this point.
+ dataset.Add (x, y, z);
+ }
+
+ // The blank line is necessary at the end of each x value's data
+ // points for the 3-D surface grid to work.
+ dataset.AddEmptyLine ();
+ }
+
+ // Add the dataset to the plot.
+ plot.AddDataset (dataset);
+
+ // Open the plot file.
+ ofstream plotFile (plotFileName.c_str());
+
+ // Write the plot file.
+ plot.GenerateOutput (plotFile);
+
+ // Close the plot file.
+ plotFile.close ();
--- a/doc/manual/source/index.rst Sat Aug 20 14:41:19 2011 -0400
+++ b/doc/manual/source/index.rst Mon Oct 17 16:59:17 2011 -0400
@@ -28,6 +28,7 @@
tracing
realtime
helpers
+ gnuplot
python
tests
support
--- a/doc/manual/source/python.rst Sat Aug 20 14:41:19 2011 -0400
+++ b/doc/manual/source/python.rst Mon Oct 17 16:59:17 2011 -0400
@@ -12,7 +12,7 @@
The goal of Python bindings for |ns3| are two fold:
-#. Allow the programmer to write complete simulation scripts in Python (http://wwww.python.org);
+#. Allow the programmer to write complete simulation scripts in Python (http://www.python.org);
#. Prototype new models (e.g. routing protocols).
For the time being, the primary focus of the bindings is the first goal, but the second goal will eventually be supported as well.
--- a/doc/release_steps.txt Sat Aug 20 14:41:19 2011 -0400
+++ b/doc/release_steps.txt Mon Oct 17 16:59:17 2011 -0400
@@ -1,12 +1,19 @@
Steps in doing an ns-3 release
+ns-3-dev preparation
+--------------------
+
1. check out a clean ns-3-dev somewhere using ns-3-allinone (you will need it)
- hg clone http://code.nsnam.org/ns-3-allinone
- ./download.py
- ./build.py --enable-examples --enable-tests
- - confirm that the release builds cleanly.
+ - try building static, optimized, and debug versions
+ - try Python visualizer (not tested by buildbots)
+ -- ./waf --pyrun src/flow-monitor/examples/wifi-olsr-flowmon.py --vis
- cd ns-3-dev
- - ensure that tests pass (./test.py)
+ - ensure that tests pass (./test.py -g) and make sure that the buildbots
+ are reporting greens based on the tip of the repository
+
2. prepare the source files
- revise and check in AUTHORS, if needed
- revise and check in RELEASE_NOTES. Make sure to edit the Availability
@@ -15,24 +22,61 @@
- confirm that Doxygen builds cleanly (./waf doxygen),
and check in any necessary changes. Currently, doxygen does not build
cleanly, we need to fix this over time.
-3. build an ns-3-allinone distribution
- - you may want to check out a clean ns-3-allinone and ns-3-dev somewhere,
- otherwise the tarball will be huge
+
+At this point, the ns-3-dev should be ready, except for changing the
+name of this repo from "3-dev" to the numbered release. That will come
+in subsequent steps.
+
+ns-allinone-3.X.tar.bz2 dry run
+-------------------------------
+
+This phase is optional to dry-run a tarball before tagging. You may skip
+to the next phase if you are ready to just make the release or release
+candidate.
+
+1. check out a clean ns-3-allinone again
- change into the allinone directory
- - ./dist.py
- - this will create an ns-allinone-dev.tar.bz2 tarball
-4. test dev tarball on release platforms
- - ./test.py
- - other scripts you can think of
-5. once you are happy with the tarball, tag ns-3-dev
+ - ./download.py
+ - cd ns-3-dev
+ - change VERSION to the appropriate string, either "3.X" (for a release) or
+ "3.X.RC1" Do not commit this VERSION change to ns-3-dev. It is used
+ by dist.py script to name the directory properly.
+ - cd into allinone directory and type "./dist.py"; you should see something
+ like this:
+
+NS-3 version: '3.12'
+Adding ns-3-dev as ns-allinone-3.12/ns-3.12
+Adding pybindgen as ns-allinone-3.12/pybindgen-0.15.0.795
+Adding nsc as ns-allinone-3.12/nsc-0.5.2
+Adding the build script files
+
+This will create an ns-allinone-3.X.tar.bz2 tarball
+
+2. test tarball on release platforms
+ - optimized, debug, and static builds
+ - ./test.py -g
+ - make latexpdf in the doc/manual, doc/models, and doc/tutorial directories
+ - ./waf --doxygen
+
+At this point, you are ready for final packaging and repository/site work
+
+tagging ns-3-dev and creating ns-3.X repositories
+-------------------------------------------------
+
+The steps here involve tagging ns-3-dev, copying over ns-3-dev to ns-3.X
+on code.nsnam.org, cloning it locally, making changes from "3-dev" to "3.X"
+in various places, and checking in those changes to the new ns-3.X repository.
+
+1. once you are happy with the tarball, tag ns-3-dev
- cd into ns-3-dev
- if release candidate
-- hg tag "ns-3.x-RCy"
- -- hg push ssh://code@code.nsnam.org//home/code/repos/ns-3.x-RCy
+ -- hg push ssh://code@code.nsnam.org//home/code/repos/ns-3-dev
- else if final release
-- hg tag "ns-3.x"
- -- hg push ssh://code@code.nsnam.org//home/code/repos/ns-3.x
-6. clone the tagged ns-3-dev and place it on the repository
+ -- hg push ssh://code@code.nsnam.org//home/code/repos/ns-3-dev
+
+2. copy the tagged ns-3-dev and place it on the repository
- ssh code.nsnam.org; sudo bash; su code;
- if release candidate
-- cp -r /home/code/repos/ns-3-dev /home/code/repos/ns-3.x-RCy
@@ -52,12 +96,15 @@
description = ns-3.x release
name = ns-3.x
contact = <ns-developers@isi.edu>
-7. If this is a final release (not RC)
- - archive ns-3.x RCs in /home/code/archived-repos
- - delete ns-3.x RCs from /home/code/repos
-8. check out a clean version of the new release (ns-3.x) or (ns-3.x-RCy) somewhere
+
+3. If this is a final release (not RC)
+ - move (mv) ns-3.x RCs in /home/code/archived-repos
+
+4. check out a clean version of the new release (ns-3.x) or (ns-3.x-RCy)
+ to your local machine
- hg clone http://code.nsnam.org/ns-3.x or (-RCy)
-9. Update the VERSION for this new release
+
+5. Update the VERSION for this new release
- change the string 3-dev in the VERSION file to the real version
(e.g. 3.7 or 3.7-RC1) This must agree with the version name you chose in the clone.
- change the version and release string for the documentation in
@@ -66,67 +113,87 @@
VERSION file.
- hg commit -m "update VERSION to ns-3.x" or (-RCy), you get the point
- hg push ssh://code@code.nsnam.org//home/code/repos/ns-3.x
-10. Run the tests on the new release (debug and optimized) like a user would
- You need to use ns-3-allinone since you will use that to make the distro
- It is convenient to let buildbot do much of this work for you, the day of
- the release
- - hg clone http://code.nsnam.org/ns-3-allinone ns-3-allinone-3.x-test
- - cd !$
+
+creating the distribution tarball
+---------------------------------
+
+1. Create final tarballs
+ You need to work with a clean ns-3-allinone-3.x directory
+ - hg clone http://code.nsnam.org/ns-3-allinone
+ - cd ns-3-allinone
- ./download.py -n ns-3.x
- - ./build.py
- - cd ns-3.x
- - ./test.py
- - ./test.py -g
- - ./waf -d optimized --enable-examples --enable-tests configure
- - ./waf
- - ./test.py
- - ./test.py -g
- - There should be no test errors at this time
-11. Create final tarballs
- You need to work with a clean ns-3-allinone-3.x directory
- - hg clone http://code.nsnam.org/ns-3-allinone ns-3-allinone-3.x
- - cd !$
- - ./download.py -n ns-3.x
- - ./dist.py
- - notice we did not build here
+ - ./dist.py (notice we did not build here)
- this will create an ns-allinone-3.x.tar.bz2 tarball
- - test this tarball out somewhere just to make sure everything went ok
-12. upload "ns-allinone-3.x.tar.bz2" to the /var/www/html/releases/ directory on
+ - sanity check this tarball just to make sure everything went ok
+
+2. upload "ns-allinone-3.x.tar.bz2" to the /var/www/html/releases/ directory on
the www.nsnam.org server
- scp ns-allinone-3.x.tar.bz2 www.nsnam.org:~
- ssh www.nsnam.org
- sudo cp ns-allinone-3.x.tar.bz2 /var/www/html/releases
- cd !$
-13. give it 644 file permissions, and user/group = apache if it is not already
+
+3. give it 644 file permissions, and user/group = apache if it is not already
- sudo chown apache:apache ns-allinone-3.x.tar.bz2
- sudo chmod 644 ns-allinone-3.x.tar.bz2
-14. if this is a final release (not RC)
+
+4. if this is a final release (not RC)
- delete RC releases from /var/www/html/releases
-15. if final release (not RC) build release documentation
+
+preparing the documentation
+----------------------------
+
+1. If final release, build release documentation
- sudo bash; su nsnam; cd /home/nsnam/bin
- - edit ./update-manual-release, ./update-tutorial-release,
- ./update-doxygen-release and make sure RELEASE variable is
- set correctly
- - run ./update-manual-release, ./update-tutorial-release,
- ./update-doxygen-release
-16. update web pages on www.nsnam.org (source is in the www/ module)
- - clone the source repo (hg clone http://code.nsnam.org/www)
- - update references to releases in html_src
- (consider "grep 'ns-3\.' *.html" for a new release)
- (consider "grep 'RCx' *.html" for a new RC)
- (consider looking at past commits to www for changes)
- - update references to releases in scripts/
- - commit and push changes
- - update roadmap on wiki
-17. update the server
- - build and update HTML directory on the server
- -- ssh www.nsnam.org; sudo bash; su nsnam;
- -- run ~/bin/update-html
-18. Final checks
+ ./update-doxygen-release ns-3.x
+ ./update-manual-release ns-3.x
+ ./update-tutorial-release ns-3.x
+
+2. Check if these new files are available on the website
+
+preparing the Wordpress-based main website
+------------------------------------------
+
+1. create a new ns-3.x page which should be visible from
+http://www.nsnam.org/ns-3.x
+- New Features
+- Download
+- Bugs Fixed
+- Documentation
+
+2. Repoint http://www.nsnam.org/releases/latest to the new page
+
+3. Update the Older Releases page to create an entry for the previous
+release (there are two such pages, one under Releases and one under
+Documentation)
+
+4. The main page http://www.nsnam.org should point to
+ns-3.x in the "Download" and "Documentation" boxes
+
+5. Create blog entry to announce release
+
+ns-3 wiki edits
+---------------
+
+1. Create ns-3.(X+1) wiki page if not done already.
+
+2. edit front page and Roadmap
+
+Bugzilla
+--------
+
+1. Add a product version "ns-3.x" to the available versions.
+
+Announcing
+----------
+
+1. Final checks
- check manual, tutorial, model, and doxygen documentation links
- download tarball from web, build and run tests for as many
targets as you can
- download release from mercurial, build and run tests for as
many targets as you can
- test and verify until you're confident the release is solid.
-19. announce to ns-developers, with summary of release notes
+
+2. announce to ns-developers and ns-3-users, with summary of release notes
+
--- a/doc/tutorial/source/conceptual-overview.rst Sat Aug 20 14:41:19 2011 -0400
+++ b/doc/tutorial/source/conceptual-overview.rst Mon Oct 17 16:59:17 2011 -0400
@@ -297,19 +297,19 @@
We will use this statement as a convenient place to talk about our Doxygen
documentation system. If you look at the project web site,
`ns-3 project
-<http://www.nsnam.org>`_, you will find a link to "Doxygen
-(ns-3-dev)" in the navigation bar. If you select this link, you will be
-taken to our documentation page for the current development release. There
-is also a link to "Doxygen (stable)" that will take you to the documentation
+<http://www.nsnam.org>`_, you will find a link to "Documentation" in the navigation bar. If you select this link, you will be
+taken to our documentation page. There
+is a link to "Latest Release" that will take you to the documentation
for the latest stable release of |ns3|.
+If you select the "API Documentation" link, you will be
+taken to the |ns3| API documentation page.
Along the left side, you will find a graphical representation of the structure
of the documentation. A good place to start is the ``NS-3 Modules``
"book" in the |ns3| navigation tree. If you expand ``Modules``
you will see a list of |ns3| module documentation. The concept of
-module here ties directly into the module include files discussed above. It
-turns out that the |ns3| logging subsystem is part of the ``core``
-module, so go ahead and expand that documentation node. Now, expand the
+module here ties directly into the module include files discussed above. The |ns3| logging subsystem is discussed in the ``C++ Constructs Used by All Modules``
+section, so go ahead and expand that documentation node. Now, expand the
``Debugging`` book and then select the ``Logging`` page.
You should now be looking at the Doxygen documentation for the Logging module.
--- a/doc/tutorial/source/tracing.rst Sat Aug 20 14:41:19 2011 -0400
+++ b/doc/tutorial/source/tracing.rst Mon Oct 17 16:59:17 2011 -0400
@@ -638,18 +638,25 @@
What Trace Sources are Available?
+++++++++++++++++++++++++++++++++
-The answer to this question is found in the |ns3| Doxygen. Go to the
-|ns3| web site `"here"
-<http://www.nsnam.org/getting_started.html>`_
-and select the "Doxygen (stable)" link "Documentation" on the navigation
-bar to the left side of the page. Expand the "Modules" book in the NS-3
-documentation tree a the upper left by clicking the "+" box. Now, expand
-the "Core" book in the tree by clicking its "+" box. You should now
-see three extremely useful links:
+The answer to this question is found in the |ns3| Doxygen. If you go to
+the project web site,
+`ns-3 project
+<http://www.nsnam.org>`_, you will find a link to "Documentation" in the navigation bar. If you select this link, you will be
+taken to our documentation page. There
+is a link to "Latest Release" that will take you to the documentation
+for the latest stable release of |ns3|.
+If you select the "API Documentation" link, you will be
+taken to the |ns3| API documentation page.
+
+Expand the "Modules" book in the NS-3
+documentation tree by clicking the "+" box. Now, expand
+the "C++ Constructs Used by All Modules" book in the tree by clicking its "+" box. You should now
+see four extremely useful links:
* The list of all trace sources
* The list of all attributes
* The list of all global values
+* Debugging
The list of interest to us here is "the list of all trace sources". Go
ahead and select that link. You will see, perhaps not too surprisingly, a
@@ -1169,7 +1176,7 @@
The first thing to think about is how we want to get the data out. What is it
that we need to trace? The first thing to do is to consult "The list of all
trace sources" to see what we have to work with. Recall that this is found
-in the |ns3| Doxygen in the "Core" Module section. If you scroll
+in the |ns3| Doxygen in the "C++ Constructs Used by All Modules" Module section. If you scroll
through the list, you will eventually find:
::
--- a/examples/routing/manet-routing-compare.cc Sat Aug 20 14:41:19 2011 -0400
+++ b/examples/routing/manet-routing-compare.cc Mon Oct 17 16:59:17 2011 -0400
@@ -342,10 +342,12 @@
//NS_LOG_INFO ("Configure Tracing.");
//tr_name = tr_name + "_" + m_protocolName +"_" + nodes + "nodes_" + sNodeSpeed + "speed_" + sNodePause + "pause_" + sRate + "rate";
- //std::ofstream ascii;
- //ascii.open ((tr_name+".tr").c_str());
- //YansWifiPhyHelper::EnableAsciiAll (ascii);
- //MobilityHelper::EnableAsciiAll (ascii);
+ //AsciiTraceHelper ascii;
+ //Ptr<OutputStreamWrapper> osw = ascii.CreateFileStream ( (tr_name + ".tr").c_str());
+ //wifiPhy.EnableAsciiAll (osw);
+ //std::ofstream os;
+ //os.open ((tr_name + ".mob").c_str());
+ //MobilityHelper::EnableAsciiAll (os);
//Ptr<FlowMonitor> flowmon;
//FlowMonitorHelper flowmonHelper;
--- a/examples/wireless/wifi-ap.py Sat Aug 20 14:41:19 2011 -0400
+++ b/examples/wireless/wifi-ap.py Mon Oct 17 16:59:17 2011 -0400
@@ -95,6 +95,8 @@
def main(argv):
+ ns.core.CommandLine().Parse(argv)
+
ns.network.Packet.EnablePrinting();
# enable rts cts all the time.
--- a/src/aodv/wscript Sat Aug 20 14:41:19 2011 -0400
+++ b/src/aodv/wscript Mon Oct 17 16:59:17 2011 -0400
@@ -23,7 +23,7 @@
'test/loopback.cc',
]
- headers = bld.new_task_gen('ns3header')
+ headers = bld.new_task_gen(features=['ns3header'])
headers.module = 'aodv'
headers.source = [
'model/aodv-id-cache.h',
--- a/src/applications/wscript Sat Aug 20 14:41:19 2011 -0400
+++ b/src/applications/wscript Mon Oct 17 16:59:17 2011 -0400
@@ -32,7 +32,7 @@
'test/udp-client-server-test.cc',
]
- headers = bld.new_task_gen('ns3header')
+ headers = bld.new_task_gen(features=['ns3header'])
headers.module = 'applications'
headers.source = [
'model/bulk-send-application.h',
--- a/src/bridge/wscript Sat Aug 20 14:41:19 2011 -0400
+++ b/src/bridge/wscript Mon Oct 17 16:59:17 2011 -0400
@@ -7,7 +7,7 @@
'model/bridge-channel.cc',
'helper/bridge-helper.cc',
]
- headers = bld.new_task_gen('ns3header')
+ headers = bld.new_task_gen(features=['ns3header'])
headers.module = 'bridge'
headers.source = [
'model/bridge-net-device.h',
--- a/src/click/examples/nsclick-routing.cc Sat Aug 20 14:41:19 2011 -0400
+++ b/src/click/examples/nsclick-routing.cc Mon Oct 17 16:59:17 2011 -0400
@@ -47,11 +47,6 @@
main (int argc, char *argv[])
{
#ifdef NS3_CLICK
-//
-// Enable logging for UdpClient and
-//
- LogComponentEnable ("NsclickRoutingClient", LOG_LEVEL_INFO);
- LogComponentEnable ("NsclickRoutingServer", LOG_LEVEL_INFO);
//
// Explicitly create the nodes required by the topology (shown above).
--- a/src/click/model/ipv4-click-routing.cc Sat Aug 20 14:41:19 2011 -0400
+++ b/src/click/model/ipv4-click-routing.cc Mon Oct 17 16:59:17 2011 -0400
@@ -224,6 +224,15 @@
}
std::string
+Ipv4ClickRouting::GetIpPrefixFromInterfaceId (int ifid)
+{
+ std::stringstream addr;
+ m_ipv4->GetAddress (ifid, 0).GetMask ().Print (addr);
+
+ return addr.str ();
+}
+
+std::string
Ipv4ClickRouting::GetMacAddressFromInterfaceId (int ifid)
{
std::stringstream addr;
@@ -252,6 +261,8 @@
{
m_simNode->curtime.tv_sec = Simulator::Now ().GetSeconds ();
m_simNode->curtime.tv_usec = Simulator::Now ().GetMicroSeconds () % 1000000;
+ NS_LOG_DEBUG ("RunClickEvent at " << m_simNode->curtime.tv_sec << " " <<
+ m_simNode->curtime.tv_usec << " " << Simulator::Now ());
simclick_click_run (m_simNode);
}
@@ -260,10 +271,10 @@
{
NS_LOG_DEBUG ("HandleScheduleFromClick at " << when->tv_sec << " " << when->tv_usec << " " << Simulator::Now ());
- double simtime = when->tv_sec + (when->tv_usec / 1.0e6);
- double simdelay = simtime - Simulator::Now ().GetMicroSeconds () / 1.0e6;
+ Time simtime = Time::FromInteger(when->tv_sec, Time::S) + Time::FromInteger(when->tv_usec, Time::US);
+ Time simdelay = simtime - Simulator::Now();
- Simulator::Schedule (Seconds (simdelay), &Ipv4ClickRouting::RunClickEvent, this);
+ Simulator::Schedule (simdelay, &Ipv4ClickRouting::RunClickEvent, this);
}
void
@@ -583,6 +594,27 @@
break;
}
+ case SIMCLICK_IPPREFIX_FROM_NAME:
+ {
+ const char *ifname = va_arg (val, const char *);
+ char *buf = va_arg (val, char *);
+ int len = va_arg (val, int);
+
+ int ifid = clickInstance->GetInterfaceId (ifname);
+
+ if (ifid >= 0)
+ {
+ retval = simstrlcpy (buf, len, clickInstance->GetIpPrefixFromInterfaceId (ifid));
+ }
+ else
+ {
+ retval = -1;
+ }
+
+ NS_LOG_DEBUG (clickInstance->GetNodeName () << " SIMCLICK_IPPREFIX_FROM_NAME: " << ifname << " " << buf << " " << len);
+ break;
+ }
+
case SIMCLICK_MACADDR_FROM_NAME:
{
const char *ifname = va_arg (val, const char *);
@@ -610,7 +642,7 @@
clickInstance->HandleScheduleFromClick (when);
retval = 0;
- NS_LOG_DEBUG (clickInstance->GetNodeName () << " SIMCLICK_SCHEDULE: " << when->tv_sec << "s and " << when->tv_usec << "usecs later.");
+ NS_LOG_DEBUG (clickInstance->GetNodeName () << " SIMCLICK_SCHEDULE at " << when->tv_sec << "s and " << when->tv_usec << "usecs.");
break;
}
--- a/src/click/model/ipv4-click-routing.h Sat Aug 20 14:41:19 2011 -0400
+++ b/src/click/model/ipv4-click-routing.h Mon Oct 17 16:59:17 2011 -0400
@@ -145,6 +145,13 @@
std::string GetIpAddressFromInterfaceId (int ifid);
/**
+ * \brief Provides for SIMCLICK_IPPREFIX_FROM_NAME
+ * \param ifid The interface ID for which the IP Prefix is required
+ * \return The IP Prefix of the interface in string format
+ */
+ std::string GetIpPrefixFromInterfaceId (int ifid);
+
+ /**
* \brief Provides for SIMCLICK_MACADDR_FROM_NAME
* \param ifid The interface ID for which the MAC Address is required
* \return The MAC Address of the interface in string format
--- a/src/click/wscript Sat Aug 20 14:41:19 2011 -0400
+++ b/src/click/wscript Mon Oct 17 16:59:17 2011 -0400
@@ -4,24 +4,32 @@
import Options
-def set_options(opt):
+def options(opt):
opt.add_option('--with-nsclick',
help=('Path to Click source or installation prefix for NS-3 Click Integration support'),
dest='with_nsclick', default=None)
+ opt.add_option('--disable-nsclick',
+ help=('Disable NS-3 Click Integration support'),
+ dest='disable_nsclick', default=False, action="store_true")
def configure(conf):
+ if Options.options.disable_nsclick:
+ conf.report_optional_feature("nsclick", "NS-3 Click Integration", False,
+ "disabled by user request")
+ return
+
if Options.options.with_nsclick:
if os.path.isdir(Options.options.with_nsclick):
- conf.check_message("libnsclick.so location", '', True, ("%s (given)" % Options.options.with_nsclick))
+ conf.msg("Checking for libnsclick.so location", ("%s (given)" % Options.options.with_nsclick))
conf.env['WITH_NSCLICK'] = os.path.abspath(Options.options.with_nsclick)
else:
nsclick_dir = os.path.join('..','click')
if os.path.isdir(nsclick_dir):
- conf.check_message("click location", '', True, ("%s (guessed)" % nsclick_dir))
+ conf.msg("Checking for click location", ("%s (guessed)" % nsclick_dir))
conf.env['WITH_NSCLICK'] = os.path.abspath(nsclick_dir)
del nsclick_dir
if not conf.env['WITH_NSCLICK']:
- conf.check_message("click location", '', False)
+ conf.msg("Checking for click location", False)
conf.report_optional_feature("nsclick", "NS-3 Click Integration", False,
"nsclick not enabled (see option --with-nsclick)")
@@ -58,7 +66,7 @@
return 0;
}
'''
- conf.env['DL'] = conf.check(mandatory=True, lib='dl', define_name='DL', uselib='DL')
+ conf.env['DL'] = conf.check(mandatory=True, lib='dl', define_name='DL', uselib_store='DL')
for tmp in ['lib', 'ns']:
libdir = os.path.abspath(os.path.join(conf.env['WITH_NSCLICK'],tmp))
@@ -66,15 +74,14 @@
conf.env.append_value('NS3_MODULE_PATH',libdir)
conf.env['LIBPATH_NSCLICK'] = [libdir]
- conf.env['CPPPATH_NSCLICK'] = [os.path.abspath(os.path.join(conf.env['WITH_NSCLICK'],'include'))]
-
- conf.env['NSCLICK'] = conf.check(fragment=test_code, lib='nsclick', uselib='NSCLICK DL')
+ conf.env['INCLUDES_NSCLICK'] = [os.path.abspath(os.path.join(conf.env['WITH_NSCLICK'],'include'))]
+ conf.env['LIB_NSCLICK'] = ['nsclick']
+ conf.env['DEFINES_NSCLICK'] = ['NS3_CLICK']
+ conf.env['NSCLICK'] = conf.check_nonfatal(fragment=test_code, use='DL NSCLICK',
+ msg="Checking for library nsclick")
conf.report_optional_feature("nsclick", "NS-3 Click Integration",
conf.env['NSCLICK'], "nsclick library not found")
- if conf.env['NSCLICK']:
- conf.env.append_value('CXXDEFINES', 'NS3_CLICK')
- conf.env.append_value('CPPPATH', conf.env['CPPPATH_NSCLICK'])
- else:
+ if not conf.env['NSCLICK']:
# Add this module to the list of modules that won't be built
# if they are enabled.
conf.env['MODULES_NOT_BUILT'].append('click')
@@ -84,8 +91,7 @@
if 'click' in bld.env['MODULES_NOT_BUILT']:
return
- module = bld.create_ns3_module('click', ['internet'])
- module.includes = '. CPPPATH_NSCLICK'
+ module = bld.create_ns3_module('click', ['core', 'network', 'internet'])
module.source = [
'model/ipv4-click-routing.cc',
'model/ipv4-l3-click-protocol.cc',
@@ -98,10 +104,10 @@
]
if bld.env['NSCLICK'] and bld.env['DL']:
- module.uselib = 'NSCLICK DL'
- module_test.uselib = 'NSCLICK DL'
+ module.use = 'NSCLICK DL'
+ module_test.use = 'NSCLICK DL'
- headers = bld.new_task_gen('ns3header')
+ headers = bld.new_task_gen(features=['ns3header'])
headers.module = 'click'
headers.source = [
'model/ipv4-click-routing.h',
--- a/src/config-store/wscript Sat Aug 20 14:41:19 2011 -0400
+++ b/src/config-store/wscript Mon Oct 17 16:59:17 2011 -0400
@@ -29,7 +29,7 @@
'model/raw-text-config.cc',
]
- headers = bld.new_task_gen('ns3header')
+ headers = bld.new_task_gen(features=['ns3header'])
headers.module = 'config-store'
headers.source = [
'model/file-config.h',
@@ -43,14 +43,11 @@
'model/model-typeid-creator.cc',
'model/display-functions.cc',
])
- module.uselib = 'GTK_CONFIG_STORE'
+ module.use.append('GTK_CONFIG_STORE')
if bld.env['ENABLE_LIBXML2']:
module.source.append ('model/xml-config.cc')
- if bld.env['ENABLE_GTK_CONFIG_STORE']:
- module.uselib = module.uselib + ' LIBXML2'
- else:
- module.uselib = 'LIBXML2'
+ module.use.append('LIBXML2')
if bld.env['ENABLE_EXAMPLES']:
bld.add_subdirs('examples')
--- a/src/core/model/int64x64-128.h Sat Aug 20 14:41:19 2011 -0400
+++ b/src/core/model/int64x64-128.h Mon Oct 17 16:59:17 2011 -0400
@@ -6,7 +6,7 @@
#include <stdint.h>
#include <math.h>
-#if defined(HAVE___UINT128_T)and !defined(HAVE_UINT128_T)
+#if defined(HAVE___UINT128_T) && !defined(HAVE_UINT128_T)
typedef __uint128_t uint128_t;
typedef __int128_t int128_t;
#endif
--- a/src/core/model/system-path.cc Sat Aug 20 14:41:19 2011 -0400
+++ b/src/core/model/system-path.cc Mon Oct 17 16:59:17 2011 -0400
@@ -1,3 +1,22 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008 INRIA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Authors: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
#include "system-path.h"
#include "fatal-error.h"
#include "assert.h"
@@ -20,6 +39,11 @@
#include <mach-o/dyld.h>
#endif /* __APPLE__ */
+#ifdef __FreeBSD__
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#endif
+
#if defined (__win32__)
#define SYSTEM_PATH_SEP "\\"
@@ -110,6 +134,20 @@
filename = buffer;
free (buffer);
}
+#elif defined (__FreeBSD__)
+ {
+ int mib[4];
+ size_t bufSize = 1024;
+ char *buf = (char *) malloc(bufSize);
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_PATHNAME;
+ mib[3] = -1;
+
+ sysctl(mib, 4, buf, &bufSize, NULL, 0);
+ filename = buf;
+ }
#endif
return Dirname (filename);
}
--- a/src/core/model/system-path.h Sat Aug 20 14:41:19 2011 -0400
+++ b/src/core/model/system-path.h Mon Oct 17 16:59:17 2011 -0400
@@ -1,3 +1,22 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008 INRIA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Authors: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
#ifndef SYSTEM_PATH
#define SYSTEM_PATH
--- a/src/core/wscript Sat Aug 20 14:41:19 2011 -0400
+++ b/src/core/wscript Mon Oct 17 16:59:17 2011 -0400
@@ -3,7 +3,7 @@
import Options
-def set_options(opt):
+def options(opt):
opt.add_option('--int64x64-as-double',
help=('Whether to use a double floating point'
' type for int64x64 values'
@@ -15,9 +15,8 @@
def configure(conf):
- a = conf.check(type_name='uint128_t', define_name='HAVE_UINT128_T')
- b = conf.check(type_name='__uint128_t', define_name='HAVE___UINT128_T')
-
+ a = conf.check_nonfatal(type_name='uint128_t', define_name='HAVE_UINT128_T')
+ b = conf.check_nonfatal(type_name='__uint128_t', define_name='HAVE___UINT128_T')
if Options.options.int64x64_as_double:
conf.define('INT64X64_USE_DOUBLE', 1)
@@ -32,20 +31,20 @@
conf.env['INT64X64_USE_CAIRO'] = 1
highprec = 'cairo 128-bit integer'
- conf.check_message_custom('high precision time', 'implementation', highprec)
+ conf.msg('Checking high precision time implementation', highprec)
- conf.check(header_name='stdint.h', define_name='HAVE_STDINT_H')
- conf.check(header_name='inttypes.h', define_name='HAVE_INTTYPES_H')
- conf.check(header_name='sys/inttypes.h', define_name='HAVE_SYS_INT_TYPES_H')
- conf.check(header_name='sys/types.h', define_name='HAVE_SYS_TYPES_H')
- conf.check(header_name='sys/stat.h', define_name='HAVE_SYS_STAT_H')
- conf.check(header_name='dirent.h', define_name='HAVE_DIRENT_H')
+ conf.check_nonfatal(header_name='stdint.h', define_name='HAVE_STDINT_H')
+ conf.check_nonfatal(header_name='inttypes.h', define_name='HAVE_INTTYPES_H')
+ conf.check_nonfatal(header_name='sys/inttypes.h', define_name='HAVE_SYS_INT_TYPES_H')
+ conf.check_nonfatal(header_name='sys/types.h', define_name='HAVE_SYS_TYPES_H')
+ conf.check_nonfatal(header_name='sys/stat.h', define_name='HAVE_SYS_STAT_H')
+ conf.check_nonfatal(header_name='dirent.h', define_name='HAVE_DIRENT_H')
- if conf.check(header_name='stdlib.h'):
+ if conf.check_nonfatal(header_name='stdlib.h'):
conf.define('HAVE_STDLIB_H', 1)
conf.define('HAVE_GETENV', 1)
- conf.check(header_name='signal.h', define_name='HAVE_SIGNAL_H')
+ conf.check_nonfatal(header_name='signal.h', define_name='HAVE_SIGNAL_H')
# Check for POSIX threads
test_env = conf.env.copy()
@@ -62,10 +61,9 @@
return 0;
}
"""
- have_pthread = conf.check(header_name='pthread.h', define_name='HAVE_PTHREAD_H',
- env=test_env, fragment=fragment,
- errmsg='Could not find pthread support (build/config.log for details)',
- mandatory=False)
+ have_pthread = conf.check_nonfatal(header_name='pthread.h', define_name='HAVE_PTHREAD_H',
+ env=test_env, fragment=fragment,
+ errmsg='Could not find pthread support (build/config.log for details)')
if have_pthread:
# darwin accepts -pthread but prints a warning saying it is ignored
if Options.platform != 'darwin' and Options.platform != 'cygwin':
@@ -79,12 +77,12 @@
conf.env['ENABLE_THREADING'],
"<pthread.h> include not detected")
- conf.check(header_name='stdint.h', define_name='HAVE_STDINT_H')
- conf.check(header_name='inttypes.h', define_name='HAVE_INTTYPES_H')
+ conf.check_nonfatal(header_name='stdint.h', define_name='HAVE_STDINT_H')
+ conf.check_nonfatal(header_name='inttypes.h', define_name='HAVE_INTTYPES_H')
- conf.check(header_name='sys/inttypes.h', define_name='HAVE_SYS_INT_TYPES_H')
+ conf.check_nonfatal(header_name='sys/inttypes.h', define_name='HAVE_SYS_INT_TYPES_H')
- if not conf.check(lib='rt', uselib='RT', define_name='HAVE_RT'):
+ if not conf.check_nonfatal(lib='rt', uselib_store='RT', define_name='HAVE_RT'):
conf.report_optional_feature("RealTime", "Real Time Simulator",
False, "librt is not available")
else:
@@ -170,7 +168,7 @@
'test/watchdog-test-suite.cc',
]
- headers = bld.new_task_gen('ns3header')
+ headers = bld.new_task_gen(features=['ns3header'])
headers.module = 'core'
headers.source = [
'model/nstime.h',
@@ -240,6 +238,7 @@
'model/vector.h',
'model/default-deleter.h',
'model/fatal-impl.h',
+ 'model/system-path.h'
]
if sys.platform == 'win32':
@@ -252,7 +251,7 @@
])
- env = bld.env_of_name('default')
+ env = bld.env
if env['INT64X64_USE_DOUBLE']:
headers.source.extend(['model/int64x64-double.h'])
elif env['INT64X64_USE_128']:
@@ -276,11 +275,8 @@
'model/realtime-simulator-impl.cc',
'model/wall-clock-synchronizer.cc',
])
- core.uselib = 'RT'
- core_test.uselib = 'RT'
- else:
- core.uselib = ''
- core_test.uselib = ''
+ core.use.append('RT')
+ core_test.use.append('RT')
if env['ENABLE_THREADING']:
core.source.extend([
@@ -289,8 +285,8 @@
'model/unix-system-mutex.cc',
'model/unix-system-condition.cc',
])
- core.uselib = core.uselib + ' PTHREAD'
- core_test.uselib = core_test.uselib + ' PTHREAD'
+ core.use.append('PTHREAD')
+ core_test.use.append('PTHREAD')
headers.source.extend([
'model/unix-fd-reader.h',
'model/system-mutex.h',
@@ -299,8 +295,8 @@
])
if env['ENABLE_GSL']:
- core.uselib = core.uselib + ' GSL GSLCBLAS M'
- core_test.uselib = core_test.uselib + ' GSL GSLCBLAS M'
+ core.use.extend(['GSL', 'GSLCBLAS', 'M'])
+ core_test.use.extend(['GSL', 'GSLCBLAS', 'M'])
core_test.source.extend(['test/rng-test-suite.cc'])
if (bld.env['ENABLE_EXAMPLES']):
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/create-module.py Mon Oct 17 16:59:17 2011 -0400
@@ -0,0 +1,207 @@
+#! /usr/bin/env python
+import sys
+from optparse import OptionParser
+import os
+
+
+WSCRIPT_TEMPLATE = '''# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+# def options(opt):
+# pass
+
+# def configure(conf):
+# conf.check_nonfatal(header_name='stdint.h', define_name='HAVE_STDINT_H')
+
+def build(bld):
+ module = bld.create_ns3_module(%(MODULE)r, ['core'])
+ module.source = [
+ 'model/%(MODULE)s.cc',
+ 'helper/%(MODULE)s-helper.cc',
+ ]
+
+ headers = bld.new_task_gen(features=['ns3header'])
+ headers.module = %(MODULE)r
+ headers.source = [
+ 'model/%(MODULE)s.h',
+ 'helper/%(MODULE)s-helper.h',
+ ]
+
+ if bld.env.ENABLE_EXAMPLES:
+ bld.add_subdirs('examples')
+
+ # bld.ns3_python_bindings()
+
+'''
+
+
+
+MODEL_CC_TEMPLATE = '''/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+
+#include "%(MODULE)s.h"
+
+namespace ns3 {
+
+/* ... */
+
+
+}
+
+'''
+
+
+
+MODEL_H_TEMPLATE = '''/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+#ifndef %(INCLUDE_GUARD)s
+#define %(INCLUDE_GUARD)s
+
+namespace ns3 {
+
+/* ... */
+
+}
+
+#endif /* %(INCLUDE_GUARD)s */
+
+'''
+
+
+
+HELPER_CC_TEMPLATE = '''/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+
+#include "%(MODULE)s-helper.h"
+
+namespace ns3 {
+
+/* ... */
+
+
+}
+
+'''
+
+
+
+HELPER_H_TEMPLATE = '''/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+#ifndef %(INCLUDE_GUARD)s
+#define %(INCLUDE_GUARD)s
+
+#include "ns3/%(MODULE)s.h"
+
+namespace ns3 {
+
+/* ... */
+
+}
+
+#endif /* %(INCLUDE_GUARD)s */
+
+'''
+
+
+EXAMPLES_WSCRIPT_TEMPLATE = '''# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+def build(bld):
+ obj = bld.create_ns3_program('%(MODULE)s-example', [%(MODULE)r])
+ obj.source = '%(MODULE)s-example.cc'
+
+'''
+
+EXAMPLE_CC_TEMPLATE = '''/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+
+#include "ns3/core-module.h"
+#include "ns3/%(MODULE)s-helper.h"
+
+using namespace ns3;
+
+
+int
+main (int argc, char *argv[])
+{
+ bool verbose = true;
+
+ CommandLine cmd;
+ cmd.AddValue ("verbose", "Tell application to log if true", verbose);
+
+ cmd.Parse (argc,argv);
+
+ /* ... */
+
+ Simulator::Run ();
+ Simulator::Destroy ();
+ return 0;
+}
+
+
+'''
+
+
+def main(argv):
+ parser = OptionParser(usage=("Usage: %prog [options] modulename\n"
+ "Utility script to create a basic template for a new ns-3 module"))
+ (options, args) = parser.parse_args()
+ if len(args) != 1:
+ parser.print_help()
+ return 1
+
+ modname = args[0]
+ assert os.path.sep not in modname
+
+ moduledir = os.path.join(os.path.dirname(__file__), modname)
+
+ if os.path.exists(moduledir):
+ print >> sys.stderr, "Module %r already exists" % (modname,)
+ return 2
+
+ os.mkdir(moduledir)
+ wscript = file(os.path.join(moduledir, "wscript"), "wt")
+ wscript.write(WSCRIPT_TEMPLATE % dict(MODULE=modname))
+ wscript.close()
+
+
+ #
+ # model
+ #
+ modeldir = os.path.join(moduledir, "model")
+ os.mkdir(modeldir)
+
+ model_cc = file(os.path.join(moduledir, "model", "%s.cc" % modname), "wt")
+ model_cc.write(MODEL_CC_TEMPLATE % dict(MODULE=modname))
+ model_cc.close()
+
+ model_h = file(os.path.join(moduledir, "model", "%s.h" % modname), "wt")
+ model_h.write(MODEL_H_TEMPLATE % dict(MODULE=modname, INCLUDE_GUARD="__%s_H__" % (modname.upper()),))
+ model_h.close()
+
+
+
+ #
+ # helper
+ #
+ helperdir = os.path.join(moduledir, "helper")
+ os.mkdir(helperdir)
+
+ helper_cc = file(os.path.join(moduledir, "helper", "%s-helper.cc" % modname), "wt")
+ helper_cc.write(HELPER_CC_TEMPLATE % dict(MODULE=modname))
+ helper_cc.close()
+
+ helper_h = file(os.path.join(moduledir, "helper", "%s-helper.h" % modname), "wt")
+ helper_h.write(HELPER_H_TEMPLATE % dict(MODULE=modname, INCLUDE_GUARD="__%s_HELPER_H__" % (modname.upper()),))
+ helper_h.close()
+
+
+ examplesdir = os.path.join(moduledir, "examples")
+ os.mkdir(examplesdir)
+
+ examples_wscript = file(os.path.join(examplesdir, "wscript"), "wt")
+ examples_wscript.write(EXAMPLES_WSCRIPT_TEMPLATE % dict(MODULE=modname))
+ examples_wscript.close()
+
+ example_cc = file(os.path.join(moduledir, "examples", "%s-example.cc" % modname), "wt")
+ example_cc.write(EXAMPLE_CC_TEMPLATE % dict(MODULE=modname))
+ example_cc.close()
+
+
+ return 0
+
+if __name__ == '__main__':
+ sys.exit(main(sys.argv))
--- a/src/csma-layout/wscript Sat Aug 20 14:41:19 2011 -0400
+++ b/src/csma-layout/wscript Mon Oct 17 16:59:17 2011 -0400
@@ -5,7 +5,7 @@
obj.source = [
'model/csma-star-helper.cc',
]
- headers = bld.new_task_gen('ns3header')
+ headers = bld.new_task_gen(features=['ns3header'])
headers.module = 'csma-layout'
headers.source = [
'model/csma-star-helper.h',
--- a/src/csma/wscript Sat Aug 20 14:41:19 2011 -0400
+++ b/src/csma/wscript Mon Oct 17 16:59:17 2011 -0400
@@ -8,7 +8,7 @@
'model/csma-channel.cc',
'helper/csma-helper.cc',
]
- headers = bld.new_task_gen('ns3header')
+ headers = bld.new_task_gen(features=['ns3header'])
headers.module = 'csma'
headers.source = [
'model/backoff.h',
--- a/src/dsdv/doc/dsdv.rst Sat Aug 20 14:41:19 2011 -0400
+++ b/src/dsdv/doc/dsdv.rst Mon Oct 17 16:59:17 2011 -0400
@@ -7,6 +7,10 @@
for MANETs developed by Charles E. Perkins and Pravin Bhagwat in 1994. It uses the hop count as metric in route
selection.
+This model was developed by
+`the ResiliNets research group <http://www.ittc.ku.edu/resilinets>`_
+at the University of Kansas. A paper on this model exists at
+`this URL <https://wiki.ittc.ku.edu/resilinets/ResiliNets_Publications#.E2.80.9CDestination-Sequenced_Distance_Vector_.28DSDV.29_Routing_Protocol_Implementation_in_ns-3.E2.80.9D>`_.
DSDV Routing Overview
*********************
--- a/src/dsdv/wscript Sat Aug 20 14:41:19 2011 -0400
+++ b/src/dsdv/wscript Mon Oct 17 16:59:17 2011 -0400
@@ -16,7 +16,7 @@
'test/dsdv-testcase.cc',
]
- headers = bld.new_task_gen('ns3header')
+ headers = bld.new_task_gen(features=['ns3header'])
headers.module = 'dsdv'
headers.source = [
'model/dsdv-rtable.h',
--- a/src/emu/examples/wscript Sat Aug 20 14:41:19 2011 -0400
+++ b/src/emu/examples/wscript Mon Oct 17 16:59:17 2011 -0400
@@ -1,7 +1,7 @@
## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
def build(bld):
- env = bld.env_of_name('default')
+ env = bld.env
if env['ENABLE_EMU']:
obj = bld.create_ns3_program('emu-udp-echo', ['emu', 'internet', 'applications'])
obj.source = 'emu-udp-echo.cc'
--- a/src/emu/wscript Sat Aug 20 14:41:19 2011 -0400
+++ b/src/emu/wscript Mon Oct 17 16:59:17 2011 -0400
@@ -4,7 +4,7 @@
def configure(conf):
if conf.env['ENABLE_THREADING']:
- conf.env['ENABLE_EMU'] = conf.check(header_name='netpacket/packet.h',
+ conf.env['ENABLE_EMU'] = conf.check_nonfatal(header_name='netpacket/packet.h',
define_name='HAVE_PACKET_H')
conf.report_optional_feature("EmuNetDevice", "Emulated Net Device",
conf.env['ENABLE_EMU'],
@@ -15,7 +15,8 @@
"needs threading support which is not available")
if conf.env['ENABLE_EMU']:
- blddir = os.path.abspath(os.path.join(conf.blddir, conf.env.variant()))
+ #blddir = conf.bldnode.abspath()
+ blddir = os.path.abspath(os.path.join(conf.bldnode.abspath(), conf.variant))
emucreatordir = os.path.abspath(os.path.join(blddir, "src/emu"))
conf.env.append_value('NS3_EXECUTABLE_PATH', emucreatordir)
else:
@@ -35,7 +36,7 @@
'helper/emu-helper.cc',
]
- headers = bld.new_task_gen('ns3header')
+ headers = bld.new_task_gen(features=['ns3header'])
headers.module = 'emu'
headers.source = [
'model/emu-net-device.h',
--- a/src/energy/bindings/modulegen__gcc_ILP32.py Sat Aug 20 14:41:19 2011 -0400
+++ b/src/energy/bindings/modulegen__gcc_ILP32.py Mon Oct 17 16:59:17 2011 -0400
@@ -25,7 +25,7 @@
## wifi-preamble.h (module 'wifi'): ns3::WifiPreamble [enumeration]
module.add_enum('WifiPreamble', ['WIFI_PREAMBLE_LONG', 'WIFI_PREAMBLE_SHORT'], import_from_module='ns.wifi')
## wifi-phy-standard.h (module 'wifi'): ns3::WifiPhyStandard [enumeration]
- module.add_enum('WifiPhyStandard', ['WIFI_PHY_STANDARD_80211a', 'WIFI_PHY_STANDARD_80211b', 'WIFI_PHY_STANDARD_80211g', 'WIFI_PHY_STANDARD_80211_10Mhz', 'WIFI_PHY_STANDARD_80211_5Mhz', 'WIFI_PHY_STANDARD_holland', 'WIFI_PHY_STANDARD_80211p_CCH', 'WIFI_PHY_STANDARD_80211p_SCH'], import_from_module='ns.wifi')
+ module.add_enum('WifiPhyStandard', ['WIFI_PHY_STANDARD_80211a', 'WIFI_PHY_STANDARD_80211b', 'WIFI_PHY_STANDARD_80211g', 'WIFI_PHY_STANDARD_80211_10MHZ', 'WIFI_PHY_STANDARD_80211_5MHZ', 'WIFI_PHY_STANDARD_holland', 'WIFI_PHY_STANDARD_80211p_CCH', 'WIFI_PHY_STANDARD_80211p_SCH'], import_from_module='ns.wifi')
## wifi-mode.h (module 'wifi'): ns3::WifiModulationClass [enumeration]
module.add_enum('WifiModulationClass', ['WIFI_MOD_CLASS_UNKNOWN', 'WIFI_MOD_CLASS_IR', 'WIFI_MOD_CLASS_FHSS', 'WIFI_MOD_CLASS_DSSS', 'WIFI_MOD_CLASS_ERP_PBCC', 'WIFI_MOD_CLASS_DSSS_OFDM', 'WIFI_MOD_CLASS_ERP_OFDM', 'WIFI_MOD_CLASS_OFDM', 'WIFI_MOD_CLASS_HT'], import_from_module='ns.wifi')
## address.h (module 'network'): ns3::Address [class]
--- a/src/energy/bindings/modulegen__gcc_LP64.py Sat Aug 20 14:41:19 2011 -0400
+++ b/src/energy/bindings/modulegen__gcc_LP64.py Mon Oct 17 16:59:17 2011 -0400
@@ -25,7 +25,7 @@
## wifi-preamble.h (module 'wifi'): ns3::WifiPreamble [enumeration]
module.add_enum('WifiPreamble', ['WIFI_PREAMBLE_LONG', 'WIFI_PREAMBLE_SHORT'], import_from_module='ns.wifi')
## wifi-phy-standard.h (module 'wifi'): ns3::WifiPhyStandard [enumeration]
- module.add_enum('WifiPhyStandard', ['WIFI_PHY_STANDARD_80211a', 'WIFI_PHY_STANDARD_80211b', 'WIFI_PHY_STANDARD_80211g', 'WIFI_PHY_STANDARD_80211_10Mhz', 'WIFI_PHY_STANDARD_80211_5Mhz', 'WIFI_PHY_STANDARD_holland', 'WIFI_PHY_STANDARD_80211p_CCH', 'WIFI_PHY_STANDARD_80211p_SCH'], import_from_module='ns.wifi')
+ module.add_enum('WifiPhyStandard', ['WIFI_PHY_STANDARD_80211a', 'WIFI_PHY_STANDARD_80211b', 'WIFI_PHY_STANDARD_80211g', 'WIFI_PHY_STANDARD_80211_10MHZ', 'WIFI_PHY_STANDARD_80211_5MHZ', 'WIFI_PHY_STANDARD_holland', 'WIFI_PHY_STANDARD_80211p_CCH', 'WIFI_PHY_STANDARD_80211p_SCH'], import_from_module='ns.wifi')
## wifi-mode.h (module 'wifi'): ns3::WifiModulationClass [enumeration]
module.add_enum('WifiModulationClass', ['WIFI_MOD_CLASS_UNKNOWN', 'WIFI_MOD_CLASS_IR', 'WIFI_MOD_CLASS_FHSS', 'WIFI_MOD_CLASS_DSSS', 'WIFI_MOD_CLASS_ERP_PBCC', 'WIFI_MOD_CLASS_DSSS_OFDM', 'WIFI_MOD_CLASS_ERP_OFDM', 'WIFI_MOD_CLASS_OFDM', 'WIFI_MOD_CLASS_HT'], import_from_module='ns.wifi')
## address.h (module 'network'): ns3::Address [class]
--- a/src/energy/wscript Sat Aug 20 14:41:19 2011 -0400
+++ b/src/energy/wscript Mon Oct 17 16:59:17 2011 -0400
@@ -25,7 +25,7 @@
'test/li-ion-energy-source-test.cc',
]
- headers = bld.new_task_gen('ns3header')
+ headers = bld.new_task_gen(features=['ns3header'])
headers.module = 'energy'
headers.source = [
'model/wifi-radio-energy-model.h',
--- a/src/flow-monitor/wscript Sat Aug 20 14:41:19 2011 -0400
+++ b/src/flow-monitor/wscript Mon Oct 17 16:59:17 2011 -0400
@@ -17,7 +17,7 @@
'test/histogram-test-suite.cc',
]
- headers = bld.new_task_gen('ns3header')
+ headers = bld.new_task_gen(features=['ns3header'])
headers.module = 'flow-monitor'
headers.source = ["model/%s" % s for s in [
'flow-monitor.h',
--- a/src/internet/doc/routing-overview.rst Sat Aug 20 14:41:19 2011 -0400
+++ b/src/internet/doc/routing-overview.rst Mon Oct 17 16:59:17 2011 -0400
@@ -156,6 +156,12 @@
Link State Advertisements are used in OSPF routing, and we follow their
formatting.
+It is important to note that all of these computations are done before
+packets are flowing in the network. In particular, there are no
+overhead or control packets being exchanged when using this implementation.
+Instead, this global route manager just walks the list of nodes to
+build the necessary information and configure each node's routing table.
+
The GlobalRouteManager populates a link state database with LSAs gathered from
the entire topology. Then, for each router in the topology, the
GlobalRouteManager executes the OSPF shortest path first (SPF) computation on
@@ -175,7 +181,12 @@
straightforward now that the underlying OSPF SPF framework is in place.
Presently, we can handle IPv4 point-to-point, numbered links, as well as shared
-broadcast (CSMA) links, and we do not do equal-cost multipath.
+broadcast (CSMA) links. Equal-cost multipath is also supported. Although
+wireless link types are supported by the implementation, note that due
+to the nature of this implementation, any channel effects will not be
+considered and the routing tables will assume that every node on the
+same shared channel is reachable from every other node (i.e. it will
+be treated like a broadcast CSMA link).
The GlobalRouteManager first walks the list of nodes and aggregates
a GlobalRouter interface to each one as follows:::
--- a/src/internet/test/ipv4-raw-test.cc Sat Aug 20 14:41:19 2011 -0400
+++ b/src/internet/test/ipv4-raw-test.cc Mon Oct 17 16:59:17 2011 -0400
@@ -44,6 +44,8 @@
#include <string>
#include <limits>
#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/types.h>
namespace ns3 {
static void
--- a/src/internet/wscript Sat Aug 20 14:41:19 2011 -0400
+++ b/src/internet/wscript Mon Oct 17 16:59:17 2011 -0400
@@ -11,7 +11,7 @@
NSC_RELEASE_NAME = "nsc-0.5.2"
-def set_options(opt):
+def options(opt):
opt.add_option('--with-nsc',
help=('Use Network Simulation Cradle, given by the indicated path,'
' to allow the use of real-world network stacks'),
@@ -32,38 +32,38 @@
# Check for the location of NSC
if Options.options.with_nsc:
if os.path.isdir(Options.options.with_nsc):
- conf.check_message("NSC location", '', True, ("%s (given)" % Options.options.with_nsc))
+ conf.msg("Checking for NSC location", ("%s (given)" % Options.options.with_nsc))
conf.env['WITH_NSC'] = os.path.abspath(Options.options.with_nsc)
else:
# ns-3-dev uses ../nsc, while ns-3 releases use ../NSC_RELEASE_NAME
nsc_dir = os.path.join('..', "nsc")
nsc_release_dir = os.path.join('..', NSC_RELEASE_NAME)
if os.path.isdir(nsc_dir):
- conf.check_message("NSC location", '', True, ("%s (guessed)" % nsc_dir))
+ conf.msg("Checking for NSC location",("%s (guessed)" % nsc_dir))
conf.env['WITH_NSC'] = os.path.abspath(nsc_dir)
elif os.path.isdir(nsc_release_dir):
- conf.check_message("NSC location", '', True, ("%s (guessed)" % nsc_release_dir))
+ conf.msg("Checking for NSC location", ("%s (guessed)" % nsc_release_dir))
conf.env['WITH_NSC'] = os.path.abspath(nsc_release_dir)
del nsc_dir
del nsc_release_dir
if not conf.env['WITH_NSC']:
- conf.check_message("NSC location", '', False)
+ conf.msg("Checking for NSC location", False)
conf.report_optional_feature("nsc", "Network Simulation Cradle", False,
"NSC not found (see option --with-nsc)")
return
- if sys.platform in ['linux2']:
+ if Options.platform in ['linux', 'freebsd']:
arch = os.uname()[4]
else:
arch = None
ok = False
- if arch in ('x86_64', 'i686', 'i586', 'i486', 'i386'):
+ if arch in ('amd64', 'x86_64', 'i686', 'i586', 'i486', 'i386'):
conf.env['NSC_ENABLED'] = True
conf.env.append_value('CXXDEFINES', 'NETWORK_SIMULATION_CRADLE')
- conf.check(mandatory=True, lib='dl', define_name='HAVE_DL', uselib='DL')
+ conf.check_nonfatal(mandatory=True, lib='dl', define_name='HAVE_DL', uselib_store='DL')
ok = True
- conf.check_message('NSC supported architecture', arch, ok)
+ conf.msg('Checking for NSC supported architecture ' + (arch or ''), ok)
if not ok:
conf.env['NSC_ENABLED'] = False
@@ -205,7 +205,7 @@
'test/udp-test.cc',
]
- headers = bld.new_task_gen('ns3header')
+ headers = bld.new_task_gen(features=['ns3header'])
headers.module = 'internet'
headers.source = [
'model/udp-header.h',
@@ -283,8 +283,8 @@
obj.source.append ('model/nsc-tcp-socket-factory-impl.cc')
obj.source.append ('model/nsc-sysctl.cc')
headers.source.append('model/nsc-tcp-l4-protocol.h')
- obj.uselib = 'DL'
- internet_test.uselib = 'DL'
+ obj.use.append('DL')
+ internet_test.use.append('DL')
if (bld.env['ENABLE_EXAMPLES']):
bld.add_subdirs('examples')
--- a/src/lte/bindings/callbacks_list.py Sat Aug 20 14:41:19 2011 -0400
+++ b/src/lte/bindings/callbacks_list.py Mon Oct 17 16:59:17 2011 -0400
@@ -1,9 +1,9 @@
callback_classes = [
+ ['void', 'ns3::Ptr<ns3::Packet const>', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty'],
['void', 'ns3::Ptr<ns3::Packet>', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty'],
['void', 'ns3::Ptr<ns3::NetDevice>', 'ns3::Ptr<ns3::Packet const>', 'unsigned short', 'ns3::Address const&', 'ns3::Address const&', 'ns3::NetDevice::PacketType', 'ns3::empty', 'ns3::empty', 'ns3::empty'],
['void', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty'],
['bool', 'ns3::Ptr<ns3::Packet>', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty'],
['bool', 'ns3::Ptr<ns3::NetDevice>', 'ns3::Ptr<ns3::Packet const>', 'unsigned short', 'ns3::Address const&', 'ns3::Address const&', 'ns3::NetDevice::PacketType', 'ns3::empty', 'ns3::empty', 'ns3::empty'],
['bool', 'ns3::Ptr<ns3::NetDevice>', 'ns3::Ptr<ns3::Packet const>', 'unsigned short', 'ns3::Address const&', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty'],
- ['void', 'ns3::Ptr<ns3::Packet const>', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty'],
]
--- a/src/lte/bindings/modulegen__gcc_ILP32.py Sat Aug 20 14:41:19 2011 -0400
+++ b/src/lte/bindings/modulegen__gcc_ILP32.py Mon Oct 17 16:59:17 2011 -0400
@@ -440,6 +440,9 @@
module.add_container('std::list< ns3::PdcchMapIdealControlMessage::IdealPdcchRecord >', 'ns3::PdcchMapIdealControlMessage::IdealPdcchRecord', container_type='list')
module.add_container('std::list< ns3::CqiIdealControlMessage::CqiFeedback >', 'ns3::CqiIdealControlMessage::CqiFeedback', container_type='list')
module.add_container('std::vector< ns3::Ptr< ns3::SpectrumPhy > >', 'ns3::Ptr< ns3::SpectrumPhy >', container_type='vector')
+ typehandlers.add_type_alias('ns3::Callback< void, ns3::Ptr< ns3::Packet const >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >', 'ns3::GenericPhyTxEndCallback')
+ typehandlers.add_type_alias('ns3::Callback< void, ns3::Ptr< ns3::Packet const >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >*', 'ns3::GenericPhyTxEndCallback*')
+ typehandlers.add_type_alias('ns3::Callback< void, ns3::Ptr< ns3::Packet const >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >&', 'ns3::GenericPhyTxEndCallback&')
typehandlers.add_type_alias('ns3::Callback< void, ns3::Ptr< ns3::Packet >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >', 'ns3::GenericPhyRxEndOkCallback')
typehandlers.add_type_alias('ns3::Callback< void, ns3::Ptr< ns3::Packet >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >*', 'ns3::GenericPhyRxEndOkCallback*')
typehandlers.add_type_alias('ns3::Callback< void, ns3::Ptr< ns3::Packet >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >&', 'ns3::GenericPhyRxEndOkCallback&')
@@ -470,18 +473,15 @@
typehandlers.add_type_alias('void ( * ) ( std::ostream & ) *', 'ns3::LogTimePrinter')
typehandlers.add_type_alias('void ( * ) ( std::ostream & ) **', 'ns3::LogTimePrinter*')
typehandlers.add_type_alias('void ( * ) ( std::ostream & ) *&', 'ns3::LogTimePrinter&')
- typehandlers.add_type_alias('ns3::Callback< bool, ns3::Ptr< ns3::Packet >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >', 'ns3::GenericPhyTxStartCallback')
- typehandlers.add_type_alias('ns3::Callback< bool, ns3::Ptr< ns3::Packet >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >*', 'ns3::GenericPhyTxStartCallback*')
- typehandlers.add_type_alias('ns3::Callback< bool, ns3::Ptr< ns3::Packet >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >&', 'ns3::GenericPhyTxStartCallback&')
typehandlers.add_type_alias('ns3::Callback< void, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >', 'ns3::GenericPhyRxEndErrorCallback')
typehandlers.add_type_alias('ns3::Callback< void, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >*', 'ns3::GenericPhyRxEndErrorCallback*')
typehandlers.add_type_alias('ns3::Callback< void, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >&', 'ns3::GenericPhyRxEndErrorCallback&')
typehandlers.add_type_alias('std::vector< double, std::allocator< double > >', 'ns3::Values')
typehandlers.add_type_alias('std::vector< double, std::allocator< double > >*', 'ns3::Values*')
typehandlers.add_type_alias('std::vector< double, std::allocator< double > >&', 'ns3::Values&')
- typehandlers.add_type_alias('ns3::Callback< void, ns3::Ptr< ns3::Packet const >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >', 'ns3::GenericPhyTxEndCallback')
- typehandlers.add_type_alias('ns3::Callback< void, ns3::Ptr< ns3::Packet const >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >*', 'ns3::GenericPhyTxEndCallback*')
- typehandlers.add_type_alias('ns3::Callback< void, ns3::Ptr< ns3::Packet const >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >&', 'ns3::GenericPhyTxEndCallback&')
+ typehandlers.add_type_alias('ns3::Callback< bool, ns3::Ptr< ns3::Packet >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >', 'ns3::GenericPhyTxStartCallback')
+ typehandlers.add_type_alias('ns3::Callback< bool, ns3::Ptr< ns3::Packet >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >*', 'ns3::GenericPhyTxStartCallback*')
+ typehandlers.add_type_alias('ns3::Callback< bool, ns3::Ptr< ns3::Packet >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >&', 'ns3::GenericPhyTxStartCallback&')
## Register a nested module for the namespace FatalImpl
@@ -4071,14 +4071,14 @@
cls.add_constructor([])
## spectrum-phy.h (module 'spectrum'): ns3::SpectrumPhy::SpectrumPhy(ns3::SpectrumPhy const & arg0) [copy constructor]
cls.add_constructor([param('ns3::SpectrumPhy const &', 'arg0')])
- ## spectrum-phy.h (module 'spectrum'): ns3::Ptr<ns3::Object> ns3::SpectrumPhy::GetDevice() [member function]
+ ## spectrum-phy.h (module 'spectrum'): ns3::Ptr<ns3::NetDevice> ns3::SpectrumPhy::GetDevice() [member function]
cls.add_method('GetDevice',
- 'ns3::Ptr< ns3::Object >',
+ 'ns3::Ptr< ns3::NetDevice >',
[],
is_pure_virtual=True, is_virtual=True)
- ## spectrum-phy.h (module 'spectrum'): ns3::Ptr<ns3::Object> ns3::SpectrumPhy::GetMobility() [member function]
+ ## spectrum-phy.h (module 'spectrum'): ns3::Ptr<ns3::MobilityModel> ns3::SpectrumPhy::GetMobility() [member function]
cls.add_method('GetMobility',
- 'ns3::Ptr< ns3::Object >',
+ 'ns3::Ptr< ns3::MobilityModel >',
[],
is_pure_virtual=True, is_virtual=True)
## spectrum-phy.h (module 'spectrum'): ns3::Ptr<ns3::SpectrumModel const> ns3::SpectrumPhy::GetRxSpectrumModel() const [member function]
@@ -4096,15 +4096,15 @@
'void',
[param('ns3::Ptr< ns3::SpectrumChannel >', 'c')],
is_pure_virtual=True, is_virtual=True)
- ## spectrum-phy.h (module 'spectrum'): void ns3::SpectrumPhy::SetDevice(ns3::Ptr<ns3::Object> d) [member function]
+ ## spectrum-phy.h (module 'spectrum'): void ns3::SpectrumPhy::SetDevice(ns3::Ptr<ns3::NetDevice> d) [member function]
cls.add_method('SetDevice',
'void',
- [param('ns3::Ptr< ns3::Object >', 'd')],
+ [param('ns3::Ptr< ns3::NetDevice >', 'd')],
is_pure_virtual=True, is_virtual=True)
- ## spectrum-phy.h (module 'spectrum'): void ns3::SpectrumPhy::SetMobility(ns3::Ptr<ns3::Object> m) [member function]
+ ## spectrum-phy.h (module 'spectrum'): void ns3::SpectrumPhy::SetMobility(ns3::Ptr<ns3::MobilityModel> m) [member function]
cls.add_method('SetMobility',
'void',
- [param('ns3::Ptr< ns3::Object >', 'm')],
+ [param('ns3::Ptr< ns3::MobilityModel >', 'm')],
is_pure_virtual=True, is_virtual=True)
## spectrum-phy.h (module 'spectrum'): void ns3::SpectrumPhy::StartRx(ns3::Ptr<ns3::PacketBurst> p, ns3::Ptr<ns3::SpectrumValue const> rxPsd, ns3::SpectrumType st, ns3::Time duration) [member function]
cls.add_method('StartRx',
@@ -5477,14 +5477,14 @@
cls.add_method('GetChannel',
'ns3::Ptr< ns3::SpectrumChannel >',
[])
- ## lte-spectrum-phy.h (module 'lte'): ns3::Ptr<ns3::Object> ns3::LteSpectrumPhy::GetDevice() [member function]
+ ## lte-spectrum-phy.h (module 'lte'): ns3::Ptr<ns3::NetDevice> ns3::LteSpectrumPhy::GetDevice() [member function]
cls.add_method('GetDevice',
- 'ns3::Ptr< ns3::Object >',
+ 'ns3::Ptr< ns3::NetDevice >',
[],
is_virtual=True)
- ## lte-spectrum-phy.h (module 'lte'): ns3::Ptr<ns3::Object> ns3::LteSpectrumPhy::GetMobility() [member function]
+ ## lte-spectrum-phy.h (module 'lte'): ns3::Ptr<ns3::MobilityModel> ns3::LteSpectrumPhy::GetMobility() [member function]
cls.add_method('GetMobility',
- 'ns3::Ptr< ns3::Object >',
+ 'ns3::Ptr< ns3::MobilityModel >',
[],
is_virtual=True)
## lte-spectrum-phy.h (module 'lte'): ns3::Ptr<ns3::SpectrumValue const> ns3::LteSpectrumPhy::GetNoisePowerSpectralDensity() [member function]
@@ -5510,10 +5510,10 @@
'void',
[param('ns3::Ptr< ns3::SpectrumChannel >', 'c')],
is_virtual=True)
- ## lte-spectrum-phy.h (module 'lte'): void ns3::LteSpectrumPhy::SetDevice(ns3::Ptr<ns3::Object> d) [member function]
+ ## lte-spectrum-phy.h (module 'lte'): void ns3::LteSpectrumPhy::SetDevice(ns3::Ptr<ns3::NetDevice> d) [member function]
cls.add_method('SetDevice',
'void',
- [param('ns3::Ptr< ns3::Object >', 'd')],
+ [param('ns3::Ptr< ns3::NetDevice >', 'd')],
is_virtual=True)
## lte-spectrum-phy.h (module 'lte'): void ns3::LteSpectrumPhy::SetGenericPhyRxEndErrorCallback(ns3::GenericPhyRxEndErrorCallback c) [member function]
cls.add_method('SetGenericPhyRxEndErrorCallback',
@@ -5531,10 +5531,10 @@
cls.add_method('SetGenericPhyTxEndCallback',
'void',
[param('ns3::GenericPhyTxEndCallback', 'c')])
- ## lte-spectrum-phy.h (module 'lte'): void ns3::LteSpectrumPhy::SetMobility(ns3::Ptr<ns3::Object> m) [member function]
+ ## lte-spectrum-phy.h (module 'lte'): void ns3::LteSpectrumPhy::SetMobility(ns3::Ptr<ns3::MobilityModel> m) [member function]
cls.add_method('SetMobility',
'void',
- [param('ns3::Ptr< ns3::Object >', 'm')],
+ [param('ns3::Ptr< ns3::MobilityModel >', 'm')],
is_virtual=True)
## lte-spectrum-phy.h (module 'lte'): void ns3::LteSpectrumPhy::SetNoisePowerSpectralDensity(ns3::Ptr<ns3::SpectrumValue const> noisePsd) [member function]
cls.add_method('SetNoisePowerSpectralDensity',
--- a/src/lte/bindings/modulegen__gcc_LP64.py Sat Aug 20 14:41:19 2011 -0400
+++ b/src/lte/bindings/modulegen__gcc_LP64.py Mon Oct 17 16:59:17 2011 -0400
@@ -440,6 +440,9 @@
module.add_container('std::list< ns3::PdcchMapIdealControlMessage::IdealPdcchRecord >', 'ns3::PdcchMapIdealControlMessage::IdealPdcchRecord', container_type='list')
module.add_container('std::list< ns3::CqiIdealControlMessage::CqiFeedback >', 'ns3::CqiIdealControlMessage::CqiFeedback', container_type='list')
module.add_container('std::vector< ns3::Ptr< ns3::SpectrumPhy > >', 'ns3::Ptr< ns3::SpectrumPhy >', container_type='vector')
+ typehandlers.add_type_alias('ns3::Callback< void, ns3::Ptr< ns3::Packet const >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >', 'ns3::GenericPhyTxEndCallback')
+ typehandlers.add_type_alias('ns3::Callback< void, ns3::Ptr< ns3::Packet const >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >*', 'ns3::GenericPhyTxEndCallback*')
+ typehandlers.add_type_alias('ns3::Callback< void, ns3::Ptr< ns3::Packet const >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >&', 'ns3::GenericPhyTxEndCallback&')
typehandlers.add_type_alias('ns3::Callback< void, ns3::Ptr< ns3::Packet >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >', 'ns3::GenericPhyRxEndOkCallback')
typehandlers.add_type_alias('ns3::Callback< void, ns3::Ptr< ns3::Packet >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >*', 'ns3::GenericPhyRxEndOkCallback*')
typehandlers.add_type_alias('ns3::Callback< void, ns3::Ptr< ns3::Packet >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >&', 'ns3::GenericPhyRxEndOkCallback&')
@@ -470,18 +473,15 @@
typehandlers.add_type_alias('void ( * ) ( std::ostream & ) *', 'ns3::LogTimePrinter')
typehandlers.add_type_alias('void ( * ) ( std::ostream & ) **', 'ns3::LogTimePrinter*')
typehandlers.add_type_alias('void ( * ) ( std::ostream & ) *&', 'ns3::LogTimePrinter&')
- typehandlers.add_type_alias('ns3::Callback< bool, ns3::Ptr< ns3::Packet >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >', 'ns3::GenericPhyTxStartCallback')
- typehandlers.add_type_alias('ns3::Callback< bool, ns3::Ptr< ns3::Packet >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >*', 'ns3::GenericPhyTxStartCallback*')
- typehandlers.add_type_alias('ns3::Callback< bool, ns3::Ptr< ns3::Packet >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >&', 'ns3::GenericPhyTxStartCallback&')
typehandlers.add_type_alias('ns3::Callback< void, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >', 'ns3::GenericPhyRxEndErrorCallback')
typehandlers.add_type_alias('ns3::Callback< void, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >*', 'ns3::GenericPhyRxEndErrorCallback*')
typehandlers.add_type_alias('ns3::Callback< void, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >&', 'ns3::GenericPhyRxEndErrorCallback&')
typehandlers.add_type_alias('std::vector< double, std::allocator< double > >', 'ns3::Values')
typehandlers.add_type_alias('std::vector< double, std::allocator< double > >*', 'ns3::Values*')
typehandlers.add_type_alias('std::vector< double, std::allocator< double > >&', 'ns3::Values&')
- typehandlers.add_type_alias('ns3::Callback< void, ns3::Ptr< ns3::Packet const >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >', 'ns3::GenericPhyTxEndCallback')
- typehandlers.add_type_alias('ns3::Callback< void, ns3::Ptr< ns3::Packet const >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >*', 'ns3::GenericPhyTxEndCallback*')
- typehandlers.add_type_alias('ns3::Callback< void, ns3::Ptr< ns3::Packet const >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >&', 'ns3::GenericPhyTxEndCallback&')
+ typehandlers.add_type_alias('ns3::Callback< bool, ns3::Ptr< ns3::Packet >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >', 'ns3::GenericPhyTxStartCallback')
+ typehandlers.add_type_alias('ns3::Callback< bool, ns3::Ptr< ns3::Packet >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >*', 'ns3::GenericPhyTxStartCallback*')
+ typehandlers.add_type_alias('ns3::Callback< bool, ns3::Ptr< ns3::Packet >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >&', 'ns3::GenericPhyTxStartCallback&')
## Register a nested module for the namespace FatalImpl
@@ -4071,14 +4071,14 @@
cls.add_constructor([])
## spectrum-phy.h (module 'spectrum'): ns3::SpectrumPhy::SpectrumPhy(ns3::SpectrumPhy const & arg0) [copy constructor]
cls.add_constructor([param('ns3::SpectrumPhy const &', 'arg0')])
- ## spectrum-phy.h (module 'spectrum'): ns3::Ptr<ns3::Object> ns3::SpectrumPhy::GetDevice() [member function]
+ ## spectrum-phy.h (module 'spectrum'): ns3::Ptr<ns3::NetDevice> ns3::SpectrumPhy::GetDevice() [member function]
cls.add_method('GetDevice',
- 'ns3::Ptr< ns3::Object >',
+ 'ns3::Ptr< ns3::NetDevice >',
[],
is_pure_virtual=True, is_virtual=True)
- ## spectrum-phy.h (module 'spectrum'): ns3::Ptr<ns3::Object> ns3::SpectrumPhy::GetMobility() [member function]
+ ## spectrum-phy.h (module 'spectrum'): ns3::Ptr<ns3::MobilityModel> ns3::SpectrumPhy::GetMobility() [member function]
cls.add_method('GetMobility',
- 'ns3::Ptr< ns3::Object >',
+ 'ns3::Ptr< ns3::MobilityModel >',
[],
is_pure_virtual=True, is_virtual=True)
## spectrum-phy.h (module 'spectrum'): ns3::Ptr<ns3::SpectrumModel const> ns3::SpectrumPhy::GetRxSpectrumModel() const [member function]
@@ -4096,15 +4096,15 @@
'void',
[param('ns3::Ptr< ns3::SpectrumChannel >', 'c')],
is_pure_virtual=True, is_virtual=True)
- ## spectrum-phy.h (module 'spectrum'): void ns3::SpectrumPhy::SetDevice(ns3::Ptr<ns3::Object> d) [member function]
+ ## spectrum-phy.h (module 'spectrum'): void ns3::SpectrumPhy::SetDevice(ns3::Ptr<ns3::NetDevice> d) [member function]
cls.add_method('SetDevice',
'void',
- [param('ns3::Ptr< ns3::Object >', 'd')],
+ [param('ns3::Ptr< ns3::NetDevice >', 'd')],
is_pure_virtual=True, is_virtual=True)
- ## spectrum-phy.h (module 'spectrum'): void ns3::SpectrumPhy::SetMobility(ns3::Ptr<ns3::Object> m) [member function]
+ ## spectrum-phy.h (module 'spectrum'): void ns3::SpectrumPhy::SetMobility(ns3::Ptr<ns3::MobilityModel> m) [member function]
cls.add_method('SetMobility',
'void',
- [param('ns3::Ptr< ns3::Object >', 'm')],
+ [param('ns3::Ptr< ns3::MobilityModel >', 'm')],
is_pure_virtual=True, is_virtual=True)
## spectrum-phy.h (module 'spectrum'): void ns3::SpectrumPhy::StartRx(ns3::Ptr<ns3::PacketBurst> p, ns3::Ptr<ns3::SpectrumValue const> rxPsd, ns3::SpectrumType st, ns3::Time duration) [member function]
cls.add_method('StartRx',
@@ -5477,14 +5477,14 @@
cls.add_method('GetChannel',
'ns3::Ptr< ns3::SpectrumChannel >',
[])
- ## lte-spectrum-phy.h (module 'lte'): ns3::Ptr<ns3::Object> ns3::LteSpectrumPhy::GetDevice() [member function]
+ ## lte-spectrum-phy.h (module 'lte'): ns3::Ptr<ns3::NetDevice> ns3::LteSpectrumPhy::GetDevice() [member function]
cls.add_method('GetDevice',
- 'ns3::Ptr< ns3::Object >',
+ 'ns3::Ptr< ns3::NetDevice >',
[],
is_virtual=True)
- ## lte-spectrum-phy.h (module 'lte'): ns3::Ptr<ns3::Object> ns3::LteSpectrumPhy::GetMobility() [member function]
+ ## lte-spectrum-phy.h (module 'lte'): ns3::Ptr<ns3::MobilityModel> ns3::LteSpectrumPhy::GetMobility() [member function]
cls.add_method('GetMobility',
- 'ns3::Ptr< ns3::Object >',
+ 'ns3::Ptr< ns3::MobilityModel >',
[],
is_virtual=True)
## lte-spectrum-phy.h (module 'lte'): ns3::Ptr<ns3::SpectrumValue const> ns3::LteSpectrumPhy::GetNoisePowerSpectralDensity() [member function]
@@ -5510,10 +5510,10 @@
'void',
[param('ns3::Ptr< ns3::SpectrumChannel >', 'c')],
is_virtual=True)
- ## lte-spectrum-phy.h (module 'lte'): void ns3::LteSpectrumPhy::SetDevice(ns3::Ptr<ns3::Object> d) [member function]
+ ## lte-spectrum-phy.h (module 'lte'): void ns3::LteSpectrumPhy::SetDevice(ns3::Ptr<ns3::NetDevice> d) [member function]
cls.add_method('SetDevice',
'void',
- [param('ns3::Ptr< ns3::Object >', 'd')],
+ [param('ns3::Ptr< ns3::NetDevice >', 'd')],
is_virtual=True)
## lte-spectrum-phy.h (module 'lte'): void ns3::LteSpectrumPhy::SetGenericPhyRxEndErrorCallback(ns3::GenericPhyRxEndErrorCallback c) [member function]
cls.add_method('SetGenericPhyRxEndErrorCallback',
@@ -5531,10 +5531,10 @@
cls.add_method('SetGenericPhyTxEndCallback',
'void',
[param('ns3::GenericPhyTxEndCallback', 'c')])
- ## lte-spectrum-phy.h (module 'lte'): void ns3::LteSpectrumPhy::SetMobility(ns3::Ptr<ns3::Object> m) [member function]
+ ## lte-spectrum-phy.h (module 'lte'): void ns3::LteSpectrumPhy::SetMobility(ns3::Ptr<ns3::MobilityModel> m) [member function]
cls.add_method('SetMobility',
'void',
- [param('ns3::Ptr< ns3::Object >', 'm')],
+ [param('ns3::Ptr< ns3::MobilityModel >', 'm')],
is_virtual=True)
## lte-spectrum-phy.h (module 'lte'): void ns3::LteSpectrumPhy::SetNoisePowerSpectralDensity(ns3::Ptr<ns3::SpectrumValue const> noisePsd) [member function]
cls.add_method('SetNoisePowerSpectralDensity',
--- a/src/lte/model/lte-spectrum-phy.cc Sat Aug 20 14:41:19 2011 -0400
+++ b/src/lte/model/lte-spectrum-phy.cc Mon Oct 17 16:59:17 2011 -0400
@@ -104,7 +104,7 @@
-Ptr<Object>
+Ptr<NetDevice>
LteSpectrumPhy::GetDevice ()
{
NS_LOG_FUNCTION (this);
@@ -112,7 +112,7 @@
}
-Ptr<Object>
+Ptr<MobilityModel>
LteSpectrumPhy::GetMobility ()
{
NS_LOG_FUNCTION (this);
@@ -121,7 +121,7 @@
void
-LteSpectrumPhy::SetDevice (Ptr<Object> d)
+LteSpectrumPhy::SetDevice (Ptr<NetDevice> d)
{
NS_LOG_FUNCTION (this << d);
m_device = d;
@@ -129,7 +129,7 @@
void
-LteSpectrumPhy::SetMobility (Ptr<Object> m)
+LteSpectrumPhy::SetMobility (Ptr<MobilityModel> m)
{
NS_LOG_FUNCTION (this << m);
m_mobility = m;
--- a/src/lte/model/lte-spectrum-phy.h Sat Aug 20 14:41:19 2011 -0400
+++ b/src/lte/model/lte-spectrum-phy.h Mon Oct 17 16:59:17 2011 -0400
@@ -65,10 +65,10 @@
// inherited from SpectrumPhy
void SetChannel (Ptr<SpectrumChannel> c);
- void SetMobility (Ptr<Object> m);
- void SetDevice (Ptr<Object> d);
- Ptr<Object> GetMobility ();
- Ptr<Object> GetDevice ();
+ void SetMobility (Ptr<MobilityModel> m);
+ void SetDevice (Ptr<NetDevice> d);
+ Ptr<MobilityModel> GetMobility ();
+ Ptr<NetDevice> GetDevice ();
Ptr<const SpectrumModel> GetRxSpectrumModel () const;
/**
@@ -182,9 +182,9 @@
EventId m_endRxEventId;
- Ptr<Object> m_mobility;
+ Ptr<MobilityModel> m_mobility;
- Ptr<Object> m_device;
+ Ptr<NetDevice> m_device;
Ptr<SpectrumChannel> m_channel;
--- a/src/lte/wscript Sat Aug 20 14:41:19 2011 -0400
+++ b/src/lte/wscript Mon Oct 17 16:59:17 2011 -0400
@@ -47,7 +47,7 @@
'test/lte-propagation-loss-model-test.cc',
]
- headers = bld.new_task_gen('ns3header')
+ headers = bld.new_task_gen(features=['ns3header'])
headers.module = 'lte'
headers.source = [
'model/lte-spectrum-phy.h',
--- a/src/mesh/bindings/modulegen__gcc_ILP32.py Sat Aug 20 14:41:19 2011 -0400
+++ b/src/mesh/bindings/modulegen__gcc_ILP32.py Mon Oct 17 16:59:17 2011 -0400
@@ -27,7 +27,7 @@
## wifi-mode.h (module 'wifi'): ns3::WifiModulationClass [enumeration]
module.add_enum('WifiModulationClass', ['WIFI_MOD_CLASS_UNKNOWN', 'WIFI_MOD_CLASS_IR', 'WIFI_MOD_CLASS_FHSS', 'WIFI_MOD_CLASS_DSSS', 'WIFI_MOD_CLASS_ERP_PBCC', 'WIFI_MOD_CLASS_DSSS_OFDM', 'WIFI_MOD_CLASS_ERP_OFDM', 'WIFI_MOD_CLASS_OFDM', 'WIFI_MOD_CLASS_HT'], import_from_module='ns.wifi')
## wifi-phy-standard.h (module 'wifi'): ns3::WifiPhyStandard [enumeration]
- module.add_enum('WifiPhyStandard', ['WIFI_PHY_STANDARD_80211a', 'WIFI_PHY_STANDARD_80211b', 'WIFI_PHY_STANDARD_80211g', 'WIFI_PHY_STANDARD_80211_10Mhz', 'WIFI_PHY_STANDARD_80211_5Mhz', 'WIFI_PHY_STANDARD_holland', 'WIFI_PHY_STANDARD_80211p_CCH', 'WIFI_PHY_STANDARD_80211p_SCH'], import_from_module='ns.wifi')
+ module.add_enum('WifiPhyStandard', ['WIFI_PHY_STANDARD_80211a', 'WIFI_PHY_STANDARD_80211b', 'WIFI_PHY_STANDARD_80211g', 'WIFI_PHY_STANDARD_80211_10MHZ', 'WIFI_PHY_STANDARD_80211_5MHZ', 'WIFI_PHY_STANDARD_holland', 'WIFI_PHY_STANDARD_80211p_CCH', 'WIFI_PHY_STANDARD_80211p_SCH'], import_from_module='ns.wifi')
## wifi-mode.h (module 'wifi'): ns3::WifiCodeRate [enumeration]
module.add_enum('WifiCodeRate', ['WIFI_CODE_RATE_UNDEFINED', 'WIFI_CODE_RATE_3_4', 'WIFI_CODE_RATE_2_3', 'WIFI_CODE_RATE_1_2'], import_from_module='ns.wifi')
## qos-utils.h (module 'wifi'): ns3::AcIndex [enumeration]
--- a/src/mesh/bindings/modulegen__gcc_LP64.py Sat Aug 20 14:41:19 2011 -0400
+++ b/src/mesh/bindings/modulegen__gcc_LP64.py Mon Oct 17 16:59:17 2011 -0400
@@ -27,7 +27,7 @@
## wifi-mode.h (module 'wifi'): ns3::WifiModulationClass [enumeration]
module.add_enum('WifiModulationClass', ['WIFI_MOD_CLASS_UNKNOWN', 'WIFI_MOD_CLASS_IR', 'WIFI_MOD_CLASS_FHSS', 'WIFI_MOD_CLASS_DSSS', 'WIFI_MOD_CLASS_ERP_PBCC', 'WIFI_MOD_CLASS_DSSS_OFDM', 'WIFI_MOD_CLASS_ERP_OFDM', 'WIFI_MOD_CLASS_OFDM', 'WIFI_MOD_CLASS_HT'], import_from_module='ns.wifi')
## wifi-phy-standard.h (module 'wifi'): ns3::WifiPhyStandard [enumeration]
- module.add_enum('WifiPhyStandard', ['WIFI_PHY_STANDARD_80211a', 'WIFI_PHY_STANDARD_80211b', 'WIFI_PHY_STANDARD_80211g', 'WIFI_PHY_STANDARD_80211_10Mhz', 'WIFI_PHY_STANDARD_80211_5Mhz', 'WIFI_PHY_STANDARD_holland', 'WIFI_PHY_STANDARD_80211p_CCH', 'WIFI_PHY_STANDARD_80211p_SCH'], import_from_module='ns.wifi')
+ module.add_enum('WifiPhyStandard', ['WIFI_PHY_STANDARD_80211a', 'WIFI_PHY_STANDARD_80211b', 'WIFI_PHY_STANDARD_80211g', 'WIFI_PHY_STANDARD_80211_10MHZ', 'WIFI_PHY_STANDARD_80211_5MHZ', 'WIFI_PHY_STANDARD_holland', 'WIFI_PHY_STANDARD_80211p_CCH', 'WIFI_PHY_STANDARD_80211p_SCH'], import_from_module='ns.wifi')
## wifi-mode.h (module 'wifi'): ns3::WifiCodeRate [enumeration]
module.add_enum('WifiCodeRate', ['WIFI_CODE_RATE_UNDEFINED', 'WIFI_CODE_RATE_3_4', 'WIFI_CODE_RATE_2_3', 'WIFI_CODE_RATE_1_2'], import_from_module='ns.wifi')
## qos-utils.h (module 'wifi'): ns3::AcIndex [enumeration]
--- a/src/mesh/wscript Sat Aug 20 14:41:19 2011 -0400
+++ b/src/mesh/wscript Mon Oct 17 16:59:17 2011 -0400
@@ -53,7 +53,7 @@
'test/flame/regression.cc',
]
- headers = bld.new_task_gen('ns3header')
+ headers = bld.new_task_gen(features=['ns3header'])
headers.module = 'mesh'
headers.source = [
'model/mesh-information-element.h',
--- a/src/mobility/wscript Sat Aug 20 14:41:19 2011 -0400
+++ b/src/mobility/wscript Mon Oct 17 16:59:17 2011 -0400
@@ -30,7 +30,7 @@
'test/waypoint-mobility-model-test.cc',
]
- headers = bld.new_task_gen('ns3header')
+ headers = bld.new_task_gen(features=['ns3header'])
headers.module = 'mobility'
headers.source = [
'model/box.h',
--- a/src/mpi/model/mpi-interface.h Sat Aug 20 14:41:19 2011 -0400
+++ b/src/mpi/model/mpi-interface.h Mon Oct 17 16:59:17 2011 -0400
@@ -28,8 +28,14 @@
#include "ns3/nstime.h"
#include "ns3/buffer.h"
+#if defined(NS3_OPENMPI)
struct ompi_request_t;
typedef struct ompi_request_t* MPI_Request;
+#elif defined(NS3_MPICH)
+typedef int MPI_Request;
+#else
+typedef void* MPI_Request;
+#endif
namespace ns3 {
--- a/src/mpi/wscript Sat Aug 20 14:41:19 2011 -0400
+++ b/src/mpi/wscript Mon Oct 17 16:59:17 2011 -0400
@@ -2,34 +2,36 @@
import sys
import subprocess
import Options
-
+from waflib.Errors import WafError
def configure(conf):
- env = conf.env
- conf.find_program('mpic++', var='MPI')
- if Options.options.enable_mpi and conf.env['MPI']:
- p = subprocess.Popen([conf.env['MPI'], '-showme:compile'], stdout=subprocess.PIPE)
- flags = p.stdout.read().rstrip().split()
- p.wait()
- env.append_value("CXXFLAGS_MPI", flags)
-
- p = subprocess.Popen([conf.env['MPI'], '-showme:link'], stdout=subprocess.PIPE)
- flags = p.stdout.read().rstrip().split()
- p.wait()
- env.append_value("LINKFLAGS_MPI", flags)
-
- env.append_value('CXXDEFINES', 'NS3_MPI')
- conf.report_optional_feature("mpi", "MPI Support", True, '')
- conf.env['ENABLE_MPI'] = True
+ if Options.options.enable_mpi:
+ # try to detect openmpi installation
+ mpi = conf.check_cfg(path='mpic++', args='-showme',
+ package='', uselib_store='MPI', mandatory=False)
+ if mpi:
+ conf.env.append_value('DEFINES_MPI', 'NS3_OPENMPI')
+ else:
+ # try the MPICH2 flags
+ mpi = conf.check_cfg(path='mpic++', args='-compile-info -link-info',
+ package='', uselib_store='MPI', mandatory=False)
+ if mpi:
+ conf.env.append_value('DEFINES_MPI', 'NS3_MPICH')
+ if mpi:
+ conf.env.append_value('DEFINES_MPI', 'NS3_MPI')
+ conf.env['ENABLE_MPI'] = True
+ for libpath in conf.env.LIBPATH_MPI:
+ if 'mpi' in libpath:
+ conf.env.append_value('LINKFLAGS_MPI', '-Wl,-rpath='+libpath)
+ conf.report_optional_feature("mpi", "MPI Support", True, '')
+ else:
+ conf.report_optional_feature("mpi", "MPI Support", False, 'mpic++ not found')
else:
- if Options.options.enable_mpi:
- conf.report_optional_feature("mpi", "MPI Support", False, 'mpic++ not found')
- else:
- conf.report_optional_feature("mpi", "MPI Support", False, 'option --enable-mpi not selected')
+ conf.report_optional_feature("mpi", "MPI Support", False, 'option --enable-mpi not selected')
def build(bld):
- env = bld.env_of_name('default')
+ env = bld.env
sim = bld.create_ns3_module('mpi', ['core', 'network'])
sim.source = [
'model/distributed-simulator-impl.cc',
@@ -37,7 +39,7 @@
'model/mpi-receiver.cc',
]
- headers = bld.new_task_gen('ns3header')
+ headers = bld.new_task_gen(features=['ns3header'])
headers.module = 'mpi'
headers.source = [
'model/distributed-simulator-impl.h',
@@ -46,7 +48,7 @@
]
if env['ENABLE_MPI']:
- sim.uselib = 'MPI'
+ sim.use.append('MPI')
if bld.env['ENABLE_EXAMPLES']:
bld.add_subdirs('examples')
--- a/src/netanim/bindings/modulegen__gcc_ILP32.py Sat Aug 20 14:41:19 2011 -0400
+++ b/src/netanim/bindings/modulegen__gcc_ILP32.py Mon Oct 17 16:59:17 2011 -0400
@@ -488,6 +488,14 @@
cls.add_constructor([])
## animation-interface-helper.h (module 'netanim'): ns3::AnimRxInfo::AnimRxInfo(ns3::Time const & fbRx, ns3::Ptr<ns3::NetDevice const> nd, double rxRange) [constructor]
cls.add_constructor([param('ns3::Time const &', 'fbRx'), param('ns3::Ptr< ns3::NetDevice const >', 'nd'), param('double', 'rxRange')])
+ ## animation-interface-helper.h (module 'netanim'): bool ns3::AnimRxInfo::IsPhyRxComplete() [member function]
+ cls.add_method('IsPhyRxComplete',
+ 'bool',
+ [])
+ ## animation-interface-helper.h (module 'netanim'): void ns3::AnimRxInfo::SetPhyRxComplete() [member function]
+ cls.add_method('SetPhyRxComplete',
+ 'void',
+ [])
## animation-interface-helper.h (module 'netanim'): ns3::AnimRxInfo::m_fbRx [variable]
cls.add_instance_attribute('m_fbRx', 'double', is_const=False)
## animation-interface-helper.h (module 'netanim'): ns3::AnimRxInfo::m_lbRx [variable]
@@ -507,6 +515,14 @@
cls.add_constructor([param('std::string const', 'filename'), param('bool', 'usingXML', default_value='true')])
## animation-interface.h (module 'netanim'): ns3::AnimationInterface::AnimationInterface(uint16_t port, bool usingXML=true) [constructor]
cls.add_constructor([param('uint16_t', 'port'), param('bool', 'usingXML', default_value='true')])
+ ## animation-interface.h (module 'netanim'): void ns3::AnimationInterface::ResetAnimWriteCallback() [member function]
+ cls.add_method('ResetAnimWriteCallback',
+ 'void',
+ [])
+ ## animation-interface.h (module 'netanim'): void ns3::AnimationInterface::SetAnimWriteCallback(void (*)( char const * ) * cb) [member function]
+ cls.add_method('SetAnimWriteCallback',
+ 'void',
+ [param('void ( * ) ( char const * ) *', 'cb')])
## animation-interface.h (module 'netanim'): void ns3::AnimationInterface::SetMobilityPollInterval(ns3::Time t) [member function]
cls.add_method('SetMobilityPollInterval',
'void',
@@ -515,6 +531,10 @@
cls.add_method('SetOutputFile',
'bool',
[param('std::string const &', 'fn')])
+ ## animation-interface.h (module 'netanim'): void ns3::AnimationInterface::SetRandomPosition(bool setRandPos) [member function]
+ cls.add_method('SetRandomPosition',
+ 'void',
+ [param('bool', 'setRandPos')])
## animation-interface.h (module 'netanim'): bool ns3::AnimationInterface::SetServerPort(uint16_t port) [member function]
cls.add_method('SetServerPort',
'bool',
--- a/src/netanim/bindings/modulegen__gcc_LP64.py Sat Aug 20 14:41:19 2011 -0400
+++ b/src/netanim/bindings/modulegen__gcc_LP64.py Mon Oct 17 16:59:17 2011 -0400
@@ -488,6 +488,14 @@
cls.add_constructor([])
## animation-interface-helper.h (module 'netanim'): ns3::AnimRxInfo::AnimRxInfo(ns3::Time const & fbRx, ns3::Ptr<ns3::NetDevice const> nd, double rxRange) [constructor]
cls.add_constructor([param('ns3::Time const &', 'fbRx'), param('ns3::Ptr< ns3::NetDevice const >', 'nd'), param('double', 'rxRange')])
+ ## animation-interface-helper.h (module 'netanim'): bool ns3::AnimRxInfo::IsPhyRxComplete() [member function]
+ cls.add_method('IsPhyRxComplete',
+ 'bool',
+ [])
+ ## animation-interface-helper.h (module 'netanim'): void ns3::AnimRxInfo::SetPhyRxComplete() [member function]
+ cls.add_method('SetPhyRxComplete',
+ 'void',
+ [])
## animation-interface-helper.h (module 'netanim'): ns3::AnimRxInfo::m_fbRx [variable]
cls.add_instance_attribute('m_fbRx', 'double', is_const=False)
## animation-interface-helper.h (module 'netanim'): ns3::AnimRxInfo::m_lbRx [variable]
@@ -507,6 +515,14 @@
cls.add_constructor([param('std::string const', 'filename'), param('bool', 'usingXML', default_value='true')])
## animation-interface.h (module 'netanim'): ns3::AnimationInterface::AnimationInterface(uint16_t port, bool usingXML=true) [constructor]
cls.add_constructor([param('uint16_t', 'port'), param('bool', 'usingXML', default_value='true')])
+ ## animation-interface.h (module 'netanim'): void ns3::AnimationInterface::ResetAnimWriteCallback() [member function]
+ cls.add_method('ResetAnimWriteCallback',
+ 'void',
+ [])
+ ## animation-interface.h (module 'netanim'): void ns3::AnimationInterface::SetAnimWriteCallback(void (*)( char const * ) * cb) [member function]
+ cls.add_method('SetAnimWriteCallback',
+ 'void',
+ [param('void ( * ) ( char const * ) *', 'cb')])
## animation-interface.h (module 'netanim'): void ns3::AnimationInterface::SetMobilityPollInterval(ns3::Time t) [member function]
cls.add_method('SetMobilityPollInterval',
'void',
@@ -515,6 +531,10 @@
cls.add_method('SetOutputFile',
'bool',
[param('std::string const &', 'fn')])
+ ## animation-interface.h (module 'netanim'): void ns3::AnimationInterface::SetRandomPosition(bool setRandPos) [member function]
+ cls.add_method('SetRandomPosition',
+ 'void',
+ [param('bool', 'setRandPos')])
## animation-interface.h (module 'netanim'): bool ns3::AnimationInterface::SetServerPort(uint16_t port) [member function]
cls.add_method('SetServerPort',
'bool',
--- a/src/netanim/examples/dumbbell-animation.cc Sat Aug 20 14:41:19 2011 -0400
+++ b/src/netanim/examples/dumbbell-animation.cc Mon Oct 17 16:59:17 2011 -0400
@@ -36,14 +36,12 @@
uint32_t nLeftLeaf = 5;
uint32_t nRightLeaf = 5;
uint32_t nLeaf = 0; // If non-zero, number of both left and right
- uint16_t port = 0; // If non zero, port to bind to for anim connection
std::string animFile; // Name of file for animation output
CommandLine cmd;
cmd.AddValue ("nLeftLeaf", "Number of left side leaf nodes", nLeftLeaf);
cmd.AddValue ("nRightLeaf","Number of right side leaf nodes", nRightLeaf);
cmd.AddValue ("nLeaf", "Number of left and right side leaf nodes", nLeaf);
- cmd.AddValue ("port", "Port Number for Remote Animation", port);
cmd.AddValue ("animFile", "File Name for Animation Output", animFile);
cmd.Parse (argc,argv);
@@ -98,14 +96,12 @@
// Create the animation object and configure for specified output
AnimationInterface anim;
- if (port > 0)
- {
- anim.SetServerPort (port);
- }
- else if (!animFile.empty ())
+ if (!animFile.empty ())
{
anim.SetOutputFile (animFile);
}
+
+ anim.SetXMLOutput ();
anim.StartAnimation ();
// Set up the acutal simulation
@@ -115,7 +111,5 @@
Simulator::Run ();
std::cout << "Destroying the simulation" << std::endl;
Simulator::Destroy ();
- std::cout << "Stopping the animation" << std::endl;
- anim.StopAnimation ();
return 0;
}
--- a/src/netanim/examples/grid-animation.cc Sat Aug 20 14:41:19 2011 -0400
+++ b/src/netanim/examples/grid-animation.cc Mon Oct 17 16:59:17 2011 -0400
@@ -35,13 +35,11 @@
uint32_t xSize = 5;
uint32_t ySize = 5;
- uint16_t port = 0;
std::string animFile;
CommandLine cmd;
cmd.AddValue ("xSize", "Number of rows of nodes", xSize);
cmd.AddValue ("ySize", "Number of columns of nodes", ySize);
- cmd.AddValue ("port", "Port Number for Remote Animation", port);
cmd.AddValue ("animFile", "File Name for Animation Output", animFile);
cmd.Parse (argc,argv);
@@ -86,14 +84,11 @@
// Create the animation object and configure for specified output
AnimationInterface anim;
- if (port > 0)
- {
- anim.SetServerPort (port);
- }
- else if (!animFile.empty ())
+ if (!animFile.empty ())
{
anim.SetOutputFile (animFile);
}
+ anim.SetXMLOutput ();
anim.StartAnimation ();
// Set up the actual simulation
--- a/src/netanim/examples/star-animation.cc Sat Aug 20 14:41:19 2011 -0400
+++ b/src/netanim/examples/star-animation.cc Mon Oct 17 16:59:17 2011 -0400
@@ -55,12 +55,10 @@
// Default number of nodes in the star. Overridable by command line argument.
//
uint32_t nSpokes = 8;
- uint32_t animPort = 0;
std::string animFile;
CommandLine cmd;
cmd.AddValue ("nSpokes", "Number of spoke nodes to place in the star", nSpokes);
- cmd.AddValue ("animPort", "Port Number for Remote Animation", animPort);
cmd.AddValue ("animFile", "File Name for Animation Output", animFile);
cmd.Parse (argc, argv);
@@ -118,14 +116,11 @@
// Create the animation object and configure for specified output
AnimationInterface anim;
- if (animPort > 0)
- {
- anim.SetServerPort (animPort);
- }
- else if (!animFile.empty ())
+ if (!animFile.empty ())
{
anim.SetOutputFile (animFile);
}
+ anim.SetXMLOutput ();
anim.StartAnimation ();
NS_LOG_INFO ("Run Simulation.");
--- a/src/netanim/helper/animation-interface-helper.cc Sat Aug 20 14:41:19 2011 -0400
+++ b/src/netanim/helper/animation-interface-helper.cc Mon Oct 17 16:59:17 2011 -0400
@@ -27,63 +27,69 @@
namespace ns3 {
AnimPacketInfo::AnimPacketInfo()
- : m_txnd (0), m_nRx (0), m_nRxEnd (0), m_fbTx (0), m_lbTx (0),
- transmitter_loc (Vector (0,0,0))
+ : m_txnd (0), m_fbTx (0), m_lbTx (0),
+ m_txLoc (Vector (0,0,0))
{
}
-AnimPacketInfo::AnimPacketInfo(Ptr<const NetDevice> nd, const Time& fbTx,
+AnimPacketInfo::AnimPacketInfo(Ptr <const NetDevice> txnd, const Time& fbTx,
const Time& lbTx, Vector txLoc)
- : m_txnd (nd), m_nRx (0), m_nRxEnd (0),
- m_fbTx (fbTx.GetSeconds ()), m_lbTx (lbTx.GetSeconds ()), transmitter_loc (txLoc),
- reception_range (0)
+ : m_txnd (txnd), m_fbTx (fbTx.GetSeconds ()), m_lbTx (lbTx.GetSeconds ()),
+ m_txLoc (txLoc)
{
}
-void AnimPacketInfo::ProcessRxBegin (Ptr<const NetDevice> nd, const Time& fbRx,
- Vector rxLoc)
+void AnimPacketInfo::ProcessRxBegin (Ptr<const NetDevice> nd, const Time& fbRx)
{
- m_rx[nd->GetNode ()->GetId ()] = AnimRxInfo (fbRx,nd);
- m_nRx++;
- reception_range = std::max (reception_range,CalculateDistance (transmitter_loc,rxLoc));
+ m_rx[nd->GetNode ()->GetId ()] = AnimRxInfo (fbRx, nd, 0);
}
-bool AnimPacketInfo::ProcessRxEnd (Ptr<const NetDevice> nd, const Time& lbRx)
-
+bool AnimPacketInfo::ProcessRxEnd (Ptr<const NetDevice> nd, const Time& lbRx, Vector rxLoc)
{
uint32_t NodeId = nd->GetNode ()->GetId ();
// Find the RxInfo
- if (m_rx.find(NodeId) != m_rx.end ())
- {
- // Check if the NetDevice matches. A node may have several NetDevices
- if (m_rx[NodeId].m_rxnd != nd)
- {
- return false;
- }
- m_rx[NodeId].m_lbRx = lbRx.GetSeconds ();
- firstlastbitDelta = m_rx[NodeId].m_lbRx - m_rx[NodeId].m_fbRx;
- m_nRxEnd++;
- if (m_nRxEnd == m_nRx)
- {
- return true;
- }
- return false; // Still more RxEnd notifications expected
+ if (m_rx.find (NodeId) == m_rx.end ())
+ {
+ return false;
+ }
+ AnimRxInfo& rxInfo = m_rx[NodeId];
+ // Check if the NetDevice matches. A node may have several NetDevices
+ if (rxInfo.m_rxnd != nd)
+ {
+ return false;
}
- NS_ASSERT ("Received RxEnd notification but RxInfo never existed");
- return false; // Still more rxEnd expected
+ rxInfo.rxRange = CalculateDistance (m_txLoc, rxLoc);
+ rxInfo.m_lbRx = lbRx.GetSeconds ();
+ rxInfo.SetPhyRxComplete ();
+ firstlastbitDelta = rxInfo.m_lbRx - rxInfo.m_fbRx;
+ return true;
+}
+
+AnimRxInfo AnimPacketInfo::GetRxInfo (Ptr<const NetDevice> nd)
+{
+ uint32_t NodeId = nd->GetNode ()->GetId ();
+ NS_ASSERT (m_rx.find (NodeId) != m_rx.end ());
+ return m_rx[NodeId];
+}
+
+void AnimPacketInfo::RemoveRxInfo (Ptr<const NetDevice> nd)
+{
+ uint32_t NodeId = nd->GetNode ()->GetId ();
+ m_rx.erase (m_rx.find (NodeId));
}
void AnimPacketInfo::ProcessRxDrop (Ptr<const NetDevice> nd)
{
- if (m_rx.find (nd->GetNode ()->GetId ()) == m_rx.end())
- {
- NS_LOG_DEBUG ("Received RxDrop notification");
- return;
- }
- // Remove any entry for which an RxBegin notification was received
- m_rx.erase (m_rx.find (nd->GetNode ()->GetId ()));
- m_nRx--;
+}
+
+bool AnimRxInfo::IsPhyRxComplete ()
+{
+ return m_PhyRxComplete;
}
+void AnimRxInfo::SetPhyRxComplete ()
+{
+ m_PhyRxComplete = true;
+}
} // namespace ns3
--- a/src/netanim/helper/animation-interface-helper.h Sat Aug 20 14:41:19 2011 -0400
+++ b/src/netanim/helper/animation-interface-helper.h Mon Oct 17 16:59:17 2011 -0400
@@ -56,27 +56,58 @@
/**
* \brief Constructor
- * \param First-bit Receive time
- * \param Ptr to NetDevice used for reception
+ * \param fbRx First-bit Receive time
+ * \param nd NetDevice where packet was received
+ * \param rxRange Reception range
*
*/
- AnimRxInfo (const Time& fbRx, Ptr <const NetDevice> nd)
- : m_fbRx (fbRx.GetSeconds ()), m_lbRx (0), m_rxnd (nd) {}
+ AnimRxInfo (const Time& fbRx, Ptr <const NetDevice> nd ,double rxRange)
+ : m_fbRx (fbRx.GetSeconds ()), m_lbRx (0), m_rxnd (nd), rxRange (rxRange), m_PhyRxComplete (false){}
- /*
- * First bit receive time
+ /**
+ * \brief First bit receive time
+ * \param m_fbRx First bit receive time
+ *
*/
double m_fbRx;
- /*
- * Last bit receive time
+ /**
+ * \brief Last bit receive time
+ * \param m_lbRx Last bit receive time
+ *
*/
double m_lbRx;
- /*
- * Ptr to receiving Net Device
+ /**
+ * \brief Ptr to receiving NetDevice
+ * \param m_rxnd Ptr to receiving NetDevice
+ *
*/
Ptr <const NetDevice> m_rxnd;
+
+ /**
+ * \brief Reception range
+ * \param rxRange Reception range
+ *
+ */
+ double rxRange;
+
+ /**
+ * \brief Check if Wifi Phy Rx is Complete
+ * \returns true if Wifi Phy Rx is complete
+ *
+ */
+ bool IsPhyRxComplete ();
+
+ /**
+ * \brief Set Wifi Phy Rx Complete
+ *
+ */
+ void SetPhyRxComplete ();
+
+private:
+ bool m_PhyRxComplete;
+
};
/**
@@ -101,88 +132,99 @@
/**
* \brief Default constructor
+ *
*/
AnimPacketInfo ();
/**
* \brief Constructor
- * \param Ptr to NetDevice transmitted on
- * \param First bit transmit time
- * \param Last bit transmit time
- * \param Transmitter Location
+ * \param tx_nd Ptr to NetDevice that is transmitting
+ * \param fbTx First bit transmit time
+ * \param lbTx Last bit transmit time
+ * \param txLoc Transmitter Location
*
*/
- AnimPacketInfo(Ptr<const NetDevice> nd,
- const Time& fbTx, const Time& lbTx,Vector txLoc);
-
+ AnimPacketInfo(Ptr <const NetDevice> tx_nd, const Time& fbTx, const Time& lbTx,Vector txLoc);
+
/**
- * Ptr to NetDevice used for transmission
- */
- Ptr<const NetDevice> m_txnd;
-
- /**
- * Number of receivers
- */
- uint32_t m_nRx;
+ * \brief Ptr to NetDevice that is transmitting
+ * \param m_txnd NetDevice that is transmitting
+ *
+ */
+ Ptr <const NetDevice> m_txnd;
/**
- * Number of RxEnd trace callbacks
- */
- uint32_t m_nRxEnd;
-
- /**
- * First bit transmission time
+ * \brief First bit transmission time
+ * \param m_fbTx First bit transmission time
+ *
*/
double m_fbTx;
/**
- * Last bit transmission time
+ * \brief Last bit transmission time
+ * \param m_lbTx Last bit transmission time
+ *
*/
double m_lbTx;
/**
- * Transmitter's location
+ * \brief Transmitter's location
+ * \param m_txLoc Transmitter's Location
+ *
*/
- Vector transmitter_loc;
+ Vector m_txLoc;
- /**
- * Receptiion range
- */
- double reception_range;
/**
- * Collection of receivers
+ * \brief Collection of receivers
+ * \param m_rx Collection of receivers
+ *
*/
std::map<uint32_t,AnimRxInfo> m_rx;
/**
* \brief Process RxBegin notifications
- * \param Ptr to NetDevice where packet was received
- * \param First bit receive time
- * \param Location of the transmitter
+ * \param nd Ptr to NetDevice where packet was received
+ * \param fbRx First bit receive time
*
*/
- void ProcessRxBegin (Ptr <const NetDevice> nd, const Time& fbRx,
- Vector rxLoc);
+ void ProcessRxBegin (Ptr <const NetDevice> nd, const Time& fbRx);
/**
* \brief Process RxEnd notifications
- * \param Ptr to NetDevice where packet was received
- * \param First bit receive time
+ * \param nd Ptr to NetDevice where packet was received
+ * \param fbRx First bit receive time
+ * \param rxLoc Location of receiver
+ * \returns true if RxEnd notification was expected and processed
*
*/
- bool ProcessRxEnd (Ptr <const NetDevice> nd, const Time& fbRx);
+ bool ProcessRxEnd (Ptr <const NetDevice> nd, const Time& fbRx, Vector rxLoc);
/**
* \brief Process RxDrop notifications
- * \param Ptr to NetDevice where packet was dropped on reception
+ * \param nd Ptr to NetDevice where packet was dropped on reception
*
*/
void ProcessRxDrop (Ptr <const NetDevice> nd);
+
+ /**
+ * \brief GetRxInfo
+ * \param nd Ptr to NetDevice where packet was received
+ * \returns AnimRxInfo object
+ *
+ */
+ AnimRxInfo GetRxInfo (Ptr <const NetDevice> nd);
+
+ /**
+ * \brief RemoveRxInfo
+ * \param nd Ptr to NetDevice where packet was received
+ *
+ */
+ void RemoveRxInfo (Ptr <const NetDevice> nd);
/**
* \brief Time delta between First bit Rx and Last bit Rx
- *
+ * \param firstlastbitDelta Time delta between First bit Rx and Last bit Rx
*/
double firstlastbitDelta;
--- a/src/netanim/model/animation-interface.cc Sat Aug 20 14:41:19 2011 -0400
+++ b/src/netanim/model/animation-interface.cc Mon Oct 17 16:59:17 2011 -0400
@@ -1,941 +1,1069 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: George F. Riley<riley@ece.gatech.edu>
- * Modified by: John Abraham <john.abraham@gatech.edu>
- */
-
-// Interface between ns3 and the network animator
-
-#include <stdio.h>
-#include <sstream>
-#include <fstream>
-#include <string>
-#include <iomanip>
-#include <map>
-
-// Socket related includes
-#ifndef WIN32
-#if defined(HAVE_SYS_SOCKET_H) && defined(HAVE_NETINET_IN_H)
-#include <sys/socket.h>
-#include <netinet/in.h>
-#else
-#include <fcntl.h>
-#endif
-#else //WIN32
-#include "winsock2.h"
-#pragma comment(lib, "ws2_32.lib")
-#include <io.h>
-#define STDOUT_FILENO GetStdHandle(STD_OUTPUT_HANDLE)
-#undef GetObject
-#undef min
-#undef max
-#define close _close
-#define write _write
-#endif
-
-
-// ns3 includes
-#include "ns3/animation-interface.h"
-#include "ns3/channel.h"
-#include "ns3/config.h"
-#include "ns3/node.h"
-#include "ns3/mobility-model.h"
-#include "ns3/packet.h"
-#include "ns3/simulator.h"
-#include "ns3/animation-interface-helper.h"
-
-NS_LOG_COMPONENT_DEFINE ("AnimationInterface");
-
-namespace ns3 {
-
-#ifndef WIN32
-AnimationInterface::AnimationInterface ()
- : m_fHandle (STDOUT_FILENO), m_xml (false), mobilitypollinterval (Seconds(0.25)),
- usingSockets (false), mport (0), outputfilename (""),
- OutputFileSet (false), ServerPortSet (false)
-{
-}
-
-AnimationInterface::AnimationInterface (const std::string fn, bool usingXML)
- : m_fHandle (STDOUT_FILENO), m_xml (usingXML), mobilitypollinterval (Seconds(0.25)),
- usingSockets (false), mport (0), outputfilename (fn),
- OutputFileSet (false), ServerPortSet (false)
-{
-}
-
-AnimationInterface::AnimationInterface (const uint16_t port, bool usingXML)
- : m_fHandle (STDOUT_FILENO), m_xml (usingXML), mobilitypollinterval (Seconds(0.25)),
- usingSockets (true), mport (port), outputfilename (""),
- OutputFileSet (false), ServerPortSet (false)
-{
-}
-
-#else
-AnimationInterface::AnimationInterface ()
- : m_fHandle ((SOCKET) STDOUT_FILENO), m_xml (false), mobilitypollinterval (Seconds(0.25)),
- usingSockets (false), mport (0), outputfilename (""),
- OutputFileSet (false), ServerPortSet (false)
-{
-}
-
-AnimationInterface::AnimationInterface (const std::string fn, bool usingXML)
- : m_fHandle ((SOCKET) STDOUT_FILENO), m_xml (usingXML), mobilitypollinterval (Seconds(0.25)),
- usingSockets (false), mport (0), outputfilename (fn),
- OutputFileSet (false), ServerPortSet (false)
-{
-}
-
-AnimationInterface::AnimationInterface (const uint16_t port, bool usingXML)
- : m_fHandle ((SOCKET) STDOUT_FILENO), m_xml (usingXML), mobilitypollinterval (Seconds(0.25)),
- usingSockets (true), mport (port), outputfilename (""),
- OutputFileSet (false), ServerPortSet (false)
-{
-}
-
-#endif
-AnimationInterface::~AnimationInterface ()
-{
- StopAnimation ();
-}
-
-void AnimationInterface::SetXMLOutput ()
-{
- NS_LOG_INFO ("XML output set");
- m_xml = true;
-}
-
-#ifndef WIN32
-bool AnimationInterface::SetOutputFile (const std::string& fn)
-{
- if (OutputFileSet)
- return true;
- FILE* f = fopen (fn.c_str (), "w");
- if (!f)
- {
- NS_FATAL_ERROR ("Unable to open Animation output file");
- return false; // Can't open
- }
- m_fHandle = fileno (f); // Set the file handle
- usingSockets = false;
- OutputFileSet = true;
- return true;
-}
-
-bool AnimationInterface::SetServerPort (uint16_t port)
-{
-#if defined(HAVE_SYS_SOCKET_H) && defined(HAVE_NETINET_IN_H)
- if (ServerPortSet)
- return;
- int s = socket (AF_INET, SOCK_STREAM, 0);
- struct sockaddr_in addr;
- addr.sin_family = AF_INET;
- addr.sin_port = htons (port);
- addr.sin_addr.s_addr = htonl (INADDR_ANY);
- if (bind (s, (struct sockaddr*)&addr, sizeof (addr)) < 0)
- {
- NS_LOG_WARN ("Can't bind to port " << port << ", exiting.");
- return false;
- }
- listen (s, 1);
- NS_LOG_INFO ("Waiting for animator connection");
- // Now wait for the animator to connect in
- m_fHandle = accept (s, 0, 0);
- NS_LOG_INFO ("Got animator connection from remote");
- // set the linger socket option
- int t = 1;
- setsockopt (s, SOL_SOCKET, SO_LINGER, &t, sizeof(t));
- usingSockets = true;
- ServerPortSet = true;
- return true;
-#endif
- return false; // never reached unless the above is disabled
- // which is done to support a platform like MinGW
-}
-
-#else
-static void PrintSocketError(std::string ErrorMessage)
-{
- std::cout<<ErrorMessage<<std::endl;
- std::cout<<"Last Error"<<GetLastError()<<std::endl;
-}
-int AcceptNetAnimConnection (uint16_t port)
-{
- WORD wVersionRequested;
- WSADATA wsaData;
- int err;
-
- /* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */
- wVersionRequested = MAKEWORD(2, 2);
-
- err = WSAStartup(wVersionRequested, &wsaData);
- if (err != 0)
- {
- PrintSocketError("WSAStartup Failed");
- return INVALID_SOCKET;
- }
- SOCKET newSocket ;
- int s = socket (AF_INET, SOCK_STREAM, 0);
- struct sockaddr_in addr;
- addr.sin_family = AF_INET;
- addr.sin_port = htons (port);
- addr.sin_addr.s_addr = htonl (INADDR_ANY);
- if (bind (s, (struct sockaddr*)&addr, sizeof (addr)) < 0)
- {
- PrintSocketError("Bind Failed");
- //NS_FATAL_ERROR("Can't bind to port ");
- return INVALID_SOCKET;
- }
- listen (s, 1);
- std::cout <<"Listening for connection from Animator"<<std::endl;
- NS_LOG_INFO ("Waiting for animator connection");
-
- // Now wait for the animator to connect in
- newSocket = accept (s, 0, 0);
- std::cout <<"Got animator connection from remote"<<std::endl;
- // set the linger socket option
- int t = 1;
- setsockopt (s, SOL_SOCKET, SO_LINGER, (char *)&t, sizeof(t));
- return newSocket;
-
-}
-
-bool AnimationInterface::SetServerPort (uint16_t port)
-{
- if (ServerPortSet)
- return true;
- if ((m_fHandle = AcceptNetAnimConnection(port))==INVALID_SOCKET)
- {
- return false;
- }
- else
- {
- usingSockets = true;
- ServerPortSet = true;
- return true ;
- }
-}
-
-bool AnimationInterface::SetOutputFile (const std::string& fn)
-{
- if (OutputFileSet)
- return true;
- HANDLE f = CreateFile(fn.c_str(), FILE_APPEND_DATA , FILE_SHARE_WRITE, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
- if (!f)
- {
- NS_FATAL_ERROR ("Unable to open Animation output file");
- return false; // Can't open
- }
- m_fHandle = (SOCKET)f; // Set the file handle
- usingSockets = false;
- OutputFileSet = true;
- return true;
-}
-#endif
-
-bool AnimationInterface::WifiPacketIsPending (uint64_t Uid)
-{
- return (pendingWifiPackets.find (Uid) != pendingWifiPackets.end ());
-}
-
-
-bool AnimationInterface::WimaxPacketIsPending (uint64_t Uid)
-{
- return (pendingWimaxPackets.find (Uid) != pendingWimaxPackets.end ());
-}
-
-void AnimationInterface::SetMobilityPollInterval (Time t)
-{
- mobilitypollinterval = t;
-}
-
-Vector AnimationInterface::UpdatePosition (Ptr <Node> n)
-{
- Ptr<MobilityModel> loc = n->GetObject<MobilityModel> ();
- Vector v(0,0,0);
- if (!loc)
- {
- return v;
- }
- if (loc)
- {
- v = loc->GetPosition ();
- }
- nodeLocation[n->GetId ()] = v;
- return v;
-}
-
-Vector AnimationInterface::UpdatePosition (Ptr <Node> n, Vector v)
-{
- nodeLocation[n->GetId ()] = v;
- return v;
-}
-
-Vector AnimationInterface::GetPosition (Ptr <Node> n)
-{
- #ifdef NS_LOG
- if (nodeLocation.find (n->GetId()) == nodeLocation.end ())
- {
- NS_FATAL_ERROR ("Node:" <<n->GetId() << " not found in Location table");
- }
- #endif
- return nodeLocation[n->GetId ()];
-}
-
-void AnimationInterface::StartAnimation ()
-{
- if (usingSockets)
- {
- SetServerPort (mport);
- }
- else
- {
- SetOutputFile (outputfilename);
- }
-
- // Find the min/max x/y for the xml topology element
- topo_minX = 0;
- topo_minY = 0;
- topo_maxX = 1000;
- topo_maxY = 1000;
- bool first = true;
- for (NodeList::Iterator i = NodeList::Begin (); i != NodeList::End (); ++i)
- {
- Ptr<Node> n = *i;
- Vector v = UpdatePosition (n);
- if (first)
- {
- topo_minX = v.x;
- topo_minY = v.y;
- topo_maxX = v.x;
- topo_maxY = v.y;
- first = false;
- }
- else
- {
- topo_minX = std::min (topo_minX, v.x);
- topo_minY = std::min (topo_minY, v.y);
- topo_maxX = std::max (topo_maxX, v.x);
- topo_maxY = std::max (topo_maxY, v.y);
- }
- }
-
- AddMargin ();
- if (m_xml)
- { // output the xml headers
- std::ostringstream oss;
- oss << GetXMLOpen_anim (0);
- oss << GetPreamble ();
- oss << GetXMLOpen_topology (topo_minX,topo_minY,topo_maxX,topo_maxY);
- WriteN (m_fHandle, oss.str ());
- }
- // Dump the topology
- for (NodeList::Iterator i = NodeList::Begin (); i != NodeList::End (); ++i)
- {
- Ptr<Node> n = *i;
- std::ostringstream oss;
- if (m_xml)
- {
- Vector v = GetPosition (n);
- oss << GetXMLOpenClose_node (0,n->GetId (),v.x,v.y);
- }
- else
- {
- // Location exists, dump it
- Vector v = GetPosition (n);
- oss << "0.0 N " << n->GetId ()
- << " " << v.x << " " << v.y << std::endl;
- }
-
- WriteN (m_fHandle, oss.str ().c_str (), oss.str ().length ());
- }
- // Now dump the p2p links
- for (NodeList::Iterator i = NodeList::Begin (); i != NodeList::End (); ++i)
- {
- Ptr<Node> n = *i;
- uint32_t n1Id = n->GetId ();
- uint32_t nDev = n->GetNDevices (); // Number of devices
- for (uint32_t i = 0; i < nDev; ++i)
- {
- Ptr<NetDevice> dev = n->GetDevice (i);
- NS_ASSERT (dev);
- Ptr<Channel> ch = dev->GetChannel ();
- if (!ch)
- {
- NS_LOG_DEBUG ("No channel can't be a p2p device");
- continue;
- }
- std::string channelType = ch->GetInstanceTypeId ().GetName ();
- if (channelType == std::string ("ns3::PointToPointChannel"))
- { // Since these are duplex links, we only need to dump
- // if srcid < dstid
- uint32_t nChDev = ch->GetNDevices ();
- for (uint32_t j = 0; j < nChDev; ++j)
- {
- Ptr<NetDevice> chDev = ch->GetDevice (j);
- uint32_t n2Id = chDev->GetNode ()->GetId ();
- if (n1Id < n2Id)
- { // ouptut the p2p link
- std::ostringstream oss;
- if (m_xml)
- {
- oss << GetXMLOpenClose_link (0,n1Id,0,n2Id);
- }
- else
- {
- oss << "0.0 L " << n1Id << " " << n2Id << std::endl;
- }
- WriteN (m_fHandle, oss.str ());
-
- }
- }
- }
- else
- {
- //NS_FATAL_ERROR ("Net animation currently only supports point-to-point links.");
- }
- }
- }
- if (m_xml)
- {
- WriteN (m_fHandle, GetXMLClose ("topology"));
- Simulator::Schedule (mobilitypollinterval, &AnimationInterface::MobilityAutoCheck, this);
- }
-
- // Connect the callbacks
- Config::Connect ("/ChannelList/*/TxRxPointToPoint",
- MakeCallback (&AnimationInterface::DevTxTrace, this));
- Config::Connect ("NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phy/PhyTxBegin",
- MakeCallback (&AnimationInterface::WifiPhyTxBeginTrace, this));
- Config::Connect ("NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phy/PhyTxEnd",
- MakeCallback (&AnimationInterface::WifiPhyTxEndTrace, this));
- Config::Connect ("NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phy/PhyRxBegin",
- MakeCallback (&AnimationInterface::WifiPhyRxBeginTrace, this));
- Config::Connect ("NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phy/PhyRxEnd",
- MakeCallback (&AnimationInterface::WifiPhyRxEndTrace, this));
- Config::Connect ("NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phy/PhyRxDrop",
- MakeCallback (&AnimationInterface::WifiPhyRxDropTrace, this));
- Config::ConnectWithoutContext ("/NodeList/*/$ns3::MobilityModel/CourseChange",
- MakeCallback (&AnimationInterface::MobilityCourseChangeTrace, this));
- Config::Connect ("/NodeList/*/DeviceList/*/$ns3::WimaxNetDevice/Tx",
- MakeCallback (&AnimationInterface::WimaxTxTrace, this));
- Config::Connect ("/NodeList/*/DeviceList/*/$ns3::WimaxNetDevice/Rx",
- MakeCallback (&AnimationInterface::WimaxRxTrace, this));
-
-
-
-}
-
-void AnimationInterface::StopAnimation ()
-{
- NS_LOG_INFO ("Stopping Animation");
- if (m_fHandle > 0)
- {
- if (m_xml)
- { // Terminate the anim element
- WriteN (m_fHandle, GetXMLClose ("anim"));
- }
-#ifndef WIN32
- close (m_fHandle);
-#else
- CloseHandle((HANDLE)m_fHandle);
-#endif
- m_fHandle = 0;
- }
-}
-
-int AnimationInterface::WriteN (int h, const std::string& st)
-{
- return WriteN (h, st.c_str (), st.length ());
-}
-
-
-// Private methods
-void AnimationInterface::AddMargin ()
-{
- // Compute width/height, and add a small margin
- double w = topo_maxX - topo_minX;
- double h = topo_maxY - topo_minY;
- topo_minX -= w * 0.05;
- topo_minY -= h * 0.05;
- topo_maxX = topo_minX + w * 1.5;
- topo_maxY = topo_minY + h * 1.5;
-}
-void AnimationInterface::RecalcTopoBounds (Vector v)
-{
- topo_minX = std::min (topo_minX, v.x);
- topo_minY = std::min (topo_minY, v.y);
- topo_maxX = std::max (topo_maxX, v.x);
- topo_maxY = std::max (topo_maxY, v.y);
-}
-
-#ifdef WIN32
-// Private methods
-int AnimationInterface::WriteN (SOCKET h, const char* data, uint32_t count)
-{ // Write count bytes to h from data
- uint32_t nLeft = count;
- const char* p = data;
- uint32_t written = 0;
-
- while (nLeft)
- {
- OVERLAPPED ovr = {0};
- int n ;
- DWORD lasterror =0;
- WriteFile((HANDLE)h,p,nLeft,(LPDWORD)&n,&ovr);
- // std::cout<<p<<std::endl;
- lasterror = GetLastError();
- // if(lasterror) std::cout<<lasterror<<std::endl;
- switch(lasterror)
- {
- case ERROR_IO_PENDING://IO is operating
- {
- GetOverlappedResult((HANDLE)h,&ovr,(LPDWORD)&n,TRUE);
-
- break;
- }
- default:
- //std::cout<<"WriteN: Last Error Code = "<<lasterror<<std::endl;
- break;
- }
- if (n <= 0)
- {
- return written;
- }
- written += n;
- nLeft -= n;
- p += n;
- }
- return written;
-}
-
-#else
-
-int AnimationInterface::WriteN (int h, const char* data, uint32_t count)
-{ // Write count bytes to h from data
- uint32_t nLeft = count;
- const char* p = data;
- uint32_t written = 0;
- while (nLeft)
- {
- int n = write (h, p, nLeft);
- if (n <= 0)
- {
- return written;
- }
- written += n;
- nLeft -= n;
- p += n;
- }
- return written;
-}
-
-#endif
-void AnimationInterface::WriteDummyPacket ()
-{
- Time now = Simulator::Now ();
- std::ostringstream oss;
- double fbTx = now.GetSeconds ();
- double lbTx = now.GetSeconds ();
- double fbRx = now.GetSeconds ();
- double lbRx = now.GetSeconds ();
- if (m_xml)
- {
- oss << GetXMLOpen_packet (0,0,fbTx,lbTx);
- oss << GetXMLOpenClose_rx (0,0,fbRx,lbRx);
- oss << GetXMLClose ("packet");
- }
- WriteN (m_fHandle, oss.str ());
-
-
-}
-void AnimationInterface::DevTxTrace (std::string context, Ptr<const Packet> p,
- Ptr<NetDevice> tx, Ptr<NetDevice> rx,
- Time txTime, Time rxTime)
-{
- NS_ASSERT (tx);
- NS_ASSERT (rx);
- Time now = Simulator::Now ();
- std::ostringstream oss;
- double fbTx = now.GetSeconds ();
- double lbTx = (now + txTime).GetSeconds ();
- double fbRx = (now + rxTime - txTime).GetSeconds ();
- double lbRx = (now + rxTime).GetSeconds ();
- if (m_xml)
- {
- oss << GetXMLOpen_packet (0,tx->GetNode ()->GetId (),fbTx,lbTx);
- oss << GetXMLOpenClose_rx (0,rx->GetNode ()->GetId (),fbRx,lbRx);
- oss << GetXMLClose ("packet");
- }
- else
- {
- oss << std::setprecision (10);
- oss << now.GetSeconds () << " P "
- << tx->GetNode ()->GetId () << " "
- << rx->GetNode ()->GetId () << " "
- << (now + txTime).GetSeconds () << " " // last bit tx time
- << (now + rxTime - txTime).GetSeconds () << " " // first bit rx time
- << (now + rxTime).GetSeconds () << std::endl; // last bit rx time
- }
- WriteN (m_fHandle, oss.str ());
-}
-
-
-Ptr <NetDevice>
-AnimationInterface::GetNetDeviceFromContext (std::string context)
-{
- // Use "NodeList/*/DeviceList/*/ as reference
- // where element [1] is the Node Id
- // element [2] is the NetDevice Id
-
- std::vector <std::string> elements = GetElementsFromContext (context);
- Ptr <Node> n = NodeList::GetNode (atoi (elements[1].c_str ()));
- NS_ASSERT (n);
- return n->GetDevice (atoi (elements[3].c_str ()));
-}
-
-void AnimationInterface::WifiPhyTxBeginTrace (std::string context,
- Ptr<const Packet> p)
-{
- Ptr <NetDevice> ndev = GetNetDeviceFromContext (context);
- NS_ASSERT (ndev);
- Ptr <Node> n = ndev->GetNode ();
- NS_ASSERT (n);
- // Add a new pending wireless
- uint64_t Uid = p->GetUid ();
- NS_LOG_INFO ("TxBeginTrace for packet:" << Uid);
- pendingWifiPackets[Uid] =
- AnimPacketInfo (ndev, Simulator::Now (), Simulator::Now (), UpdatePosition (n));
-}
-
-void AnimationInterface::WifiPhyTxEndTrace (std::string context,
- Ptr<const Packet> p)
-{
-}
-
-void AnimationInterface::WifiPhyTxDropTrace (std::string context,
- Ptr<const Packet> p)
-{
- Ptr <NetDevice> ndev = GetNetDeviceFromContext (context);
- NS_ASSERT (ndev);
- // Erase pending wifi
- uint64_t Uid = p->GetUid ();
- NS_LOG_INFO ("TxDropTrace for packet:" << Uid);
- NS_ASSERT (WifiPacketIsPending (Uid) == true);
- pendingWifiPackets.erase (pendingWifiPackets.find (Uid));
-}
-
-
-void AnimationInterface::WifiPhyRxBeginTrace (std::string context,
- Ptr<const Packet> p)
-{
- Ptr <NetDevice> ndev = GetNetDeviceFromContext (context);
- NS_ASSERT (ndev);
- Ptr <Node> n = ndev->GetNode ();
- NS_ASSERT (n);
- uint64_t Uid = p->GetUid ();
- NS_LOG_INFO ("RxBeginTrace for packet:" << Uid);
- NS_ASSERT (WifiPacketIsPending (Uid) == true);
- pendingWifiPackets[Uid].ProcessRxBegin (ndev, Simulator::Now (), UpdatePosition (n));
-}
-
-
-void AnimationInterface::WifiPhyRxEndTrace (std::string context,
- Ptr<const Packet> p)
-{
- Ptr <NetDevice> ndev = GetNetDeviceFromContext (context);
- NS_ASSERT (ndev);
- uint64_t Uid = p->GetUid ();
- NS_ASSERT (WifiPacketIsPending (Uid) == true);
- AnimPacketInfo& pkt = pendingWifiPackets[Uid];
- if (pkt.ProcessRxEnd (ndev, Simulator::Now ()))
- {
- NS_LOG_INFO ("RxEndTrace for packet:" << Uid << " complete");
- OutputWirelessPacket (Uid, pkt);
- pendingWifiPackets.erase (pendingWifiPackets.find (Uid));;
- }
-}
-
-
-void AnimationInterface::WifiPhyRxDropTrace (std::string context,
- Ptr<const Packet> p)
-{
- Ptr <NetDevice> ndev = GetNetDeviceFromContext (context);
- NS_ASSERT (ndev);
- uint64_t Uid = p->GetUid ();
- NS_LOG_INFO ("RxDropTrace for packet:"<< Uid);
- //NS_ASSERT (WifiPacketIsPending (Uid) == true);
- pendingWifiPackets[Uid].ProcessRxDrop (ndev);
-}
-
-void AnimationInterface::WimaxTxTrace (std::string context, Ptr<const Packet> p, const Mac48Address & m)
-{
- Ptr <NetDevice> ndev = GetNetDeviceFromContext (context);
- NS_ASSERT (ndev);
- Ptr <Node> n = ndev->GetNode ();
- NS_ASSERT (n);
- uint64_t Uid = p->GetUid ();
- NS_LOG_INFO ("WimaxTxTrace for packet:" << Uid);
- pendingWimaxPackets[Uid] =
- AnimPacketInfo (ndev, Simulator::Now (), Simulator::Now () + Seconds (0.0001), UpdatePosition (n));
- //HACK:TODO 0.0001 is used until Wimax implements TxBegin and TxEnd traces
-}
-
-
-void AnimationInterface::WimaxRxTrace (std::string context, Ptr<const Packet> p, const Mac48Address & m)
-{
- Ptr <NetDevice> ndev = GetNetDeviceFromContext (context);
- NS_ASSERT (ndev);
- Ptr <Node> n = ndev->GetNode ();
- NS_ASSERT (n);
- uint64_t Uid = p->GetUid ();
- NS_ASSERT (WimaxPacketIsPending (Uid) == true);
- AnimPacketInfo& pktinfo = pendingWimaxPackets[Uid];
- pktinfo.ProcessRxBegin (ndev, Simulator::Now (), UpdatePosition (n));
- pktinfo.ProcessRxEnd (ndev, Simulator::Now () + Seconds (0.0001));
- //HACK:TODO 0.0001 is used until Wimax implements RxBegin and RxEnd traces
- NS_LOG_INFO ("WimaxRxTrace for packet:" << Uid);
- OutputWirelessPacket (Uid, pktinfo);
-
-}
-
-void AnimationInterface::MobilityCourseChangeTrace (Ptr <const MobilityModel> mobility)
-
-{
- Ptr <Node> n = mobility->GetObject <Node> ();
- if (!n) return;
- if (!mobility) return;
- Vector v ;
- v = mobility->GetPosition ();
- UpdatePosition (n,v);
- RecalcTopoBounds (v);
- std::ostringstream oss;
- oss << GetXMLOpen_topology (topo_minX,topo_minY,topo_maxX,topo_maxY);
- oss << GetXMLOpenClose_node (0,n->GetId (),v.x,v.y);
- oss << GetXMLClose ("topology");
- WriteN (m_fHandle, oss.str ());
- WriteDummyPacket ();
-}
-
-bool AnimationInterface::NodeHasMoved (Ptr <Node> n, Vector newLocation)
-{
- Vector oldLocation = GetPosition (n);
- if ((ceil(oldLocation.x) == ceil(newLocation.x)) &&
- (ceil(oldLocation.y) == ceil(newLocation.y)))
- {
-
- return false;
- }
- else
- {
- return true;
- }
-}
-
-void AnimationInterface::MobilityAutoCheck ()
-{
- std::ostringstream oss;
- oss << GetXMLOpen_topology (topo_minX,topo_minY,topo_maxX,topo_maxY);
- for (NodeList::Iterator i = NodeList::Begin (); i != NodeList::End (); ++i)
- {
- Ptr <Node> n = *i;
- if (!n) continue;
- Ptr <MobilityModel> mobility = n->GetObject <MobilityModel> ();
- if (!mobility) continue;
- Vector newLocation = mobility->GetPosition ();
- if (!NodeHasMoved (n, newLocation))
- {
- continue; //Location has not changed
- }
- UpdatePosition (n, newLocation);
- RecalcTopoBounds (newLocation);
- oss << GetXMLOpenClose_node (0,n->GetId (),newLocation.x,newLocation.y);
- }
- oss << GetXMLClose ("topology");
- WriteN (m_fHandle, oss.str ());
- WriteDummyPacket ();
- if (!Simulator::IsFinished ())
- {
- Simulator::Schedule (mobilitypollinterval, &AnimationInterface::MobilityAutoCheck, this);
- }
-}
-
-
-// Helper to output a wireless packet.
-// For now, only the XML interface is supported
-
-
-std::string AnimationInterface::GetPreamble ()
-{
- std::string s =
- "<information><!-- \n\
- Description of attributes:\n\
- =========================\n\
- anim\n\
- * lp = Logical Processor Id\n\
- topology\n\
- * minX = minimum X coordinate of the canvas\n\
- * minY = minimum Y coordinate of the canvas\n\
- * maxX = maximum X coordinate of the canvas\n\
- * maxY = maximum Y coordinate of the canvas\n\
- node\n\
- * lp = Logical Processor Id\n\
- * id = Node Id\n\
- * locX = X coordinate\n\
- * locY = Y coordinate\n\
- packet\n\
- * fromLp = From logical processor Id\n\
- * fbTx = First bit transmit time\n\
- * lbTx = Last bit transmit time\n\
- rx\n\
- * toLp = To logical processor Id\n\
- * toId = To Node Id\n\
- * fbRx = First bit Rx Time\n\
- * lbRx = Last bit Rx\n\
- wpacket\n\
- * fromLp = From logical processor Id\n\
- * fromId = From Node Id\n\
- * fbTx = First bit transmit time\n\
- * lbTx = Last bit transmit time\n\
- * range = Reception range\n\
- rx\n\
- * toLp = To logical processor Id\n\
- * toId = To Node Id\n\
- * fbRx = First bit Rx time\n\
- * lbRx = Last bit Rx time-->\n\
- </information>\n";
-return s;
-}
-void AnimationInterface::OutputWirelessPacket (uint32_t uid, AnimPacketInfo& pktInfo)
-{
- if (!m_xml) return;
- std::ostringstream oss;
- RxInfoIterator p;
- uint32_t nodeId = pktInfo.m_txnd->GetNode ()->GetId ();
-
- // double lbTx = pktInfo.m_lbTx; //This is not yet implemented
- // HACK: TODO figure out lbTx from the delta of the first Rx packet
- // Ideally all Phy interfaces should have implemented TxEnd notifications
- // But currently that is not the case
-
- double lbTx = pktInfo.firstlastbitDelta + pktInfo.m_fbTx;
- oss << GetXMLOpen_wpacket (0,nodeId,pktInfo.m_fbTx,lbTx,pktInfo.reception_range);
-
- // Now add each rx
- for (p = pktInfo.m_rx.begin (); p != pktInfo.m_rx.end (); p++)
- {
- AnimRxInfo& rx = p->second;
- uint32_t rxId = rx.m_rxnd->GetNode ()->GetId ();
- if ((rx.m_lbRx - rx.m_fbRx) != pktInfo.firstlastbitDelta)
- {
- //TODO: how to handle this case elegantly?
- continue;
- }
- if (rx.m_lbRx)
- {
- oss << GetXMLOpenClose_rx (0,rxId,rx.m_fbRx,rx.m_lbRx);
- }
- }
- oss << GetXMLClose ("wpacket");
- WriteN (m_fHandle, oss.str ());
-}
-
-
-// XML Private Helpers
-
-std::string AnimationInterface::GetXMLOpen_anim (uint32_t lp)
-{
- std::ostringstream oss;
- oss <<"<anim lp = \"" << lp << "\" >\n";
- return oss.str ();
-}
-std::string AnimationInterface::GetXMLOpen_topology (double minX,double minY,double maxX,double maxY)
-{
- std::ostringstream oss;
- oss << "<topology minX = \"" << minX << "\" minY = \"" << minY
- << "\" maxX = \"" << maxX << "\" maxY = \"" << maxY
- << "\">" << std::endl;
- return oss.str ();
-
-}
-
-std::string AnimationInterface::GetXMLOpenClose_node (uint32_t lp,uint32_t id,double locX,double locY)
-{
- std::ostringstream oss;
- oss <<"<node lp = \"" << lp << "\" id = \"" << id << "\"" << " locX = \""
- << locX << "\" " << "locY = \"" << locY << "\" />\n";
- return oss.str ();
-}
-std::string AnimationInterface::GetXMLOpenClose_link (uint32_t fromLp,uint32_t fromId, uint32_t toLp, uint32_t toId)
-{
- std::ostringstream oss;
- oss << "<link fromLp=\"0\" fromId=\"" << fromId
- << "\" toLp=\"0\" toId=\"" << toId
- << "\"/>" << std::endl;
- return oss.str ();
-}
-
-
-std::string AnimationInterface::GetXMLOpen_packet (uint32_t fromLp,uint32_t fromId, double fbTx, double lbTx)
-{
- std::ostringstream oss;
- oss << std::setprecision (10);
- oss << "<packet fromLp=\"" << fromLp << "\" fromId=\"" << fromId
- << "\" fbTx=\"" << fbTx
- << "\" lbTx=\"" << lbTx
- << "\">";
- return oss.str ();
-}
-
-std::string AnimationInterface::GetXMLOpen_wpacket (uint32_t fromLp,uint32_t fromId, double fbTx, double lbTx, double range)
-{
- std::ostringstream oss;
- oss << std::setprecision (10);
- oss << "<wpacket fromLp = \"" << fromLp << "\" fromId = \"" << fromId
- << "\" fbTx = \"" << fbTx
- << "\" lbTx = \"" << lbTx
- << "\" range = \"" << range << "\">" << std::endl;
- return oss.str ();
-
-}
-
-std::string AnimationInterface::GetXMLOpenClose_rx (uint32_t toLp, uint32_t toId, double fbRx, double lbRx)
-{
- std::ostringstream oss;
- oss << std::setprecision (10);
- oss << "<rx toLp=\"" << toLp <<"\" toId=\"" << toId
- << "\" fbRx=\"" << fbRx
- << "\" lbRx=\"" << lbRx
- << "\"/>" << std::endl;
- return oss.str ();
-}
-
-std::vector<std::string> AnimationInterface::GetElementsFromContext (std::string context)
-{
- std::vector <std::string> elements;
- size_t pos1=0, pos2;
- while (pos1 != context.npos)
- {
- pos1 = context.find ("/",pos1);
- pos2 = context.find ("/",pos1+1);
- elements.push_back (context.substr (pos1+1,pos2-(pos1+1)));
- pos1 = pos2;
- pos2 = context.npos;
- }
- return elements;
-}
-
-
-} // namespace ns3
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: George F. Riley<riley@ece.gatech.edu>
+ * Modified by: John Abraham <john.abraham@gatech.edu>
+ */
+
+// Interface between ns3 and the network animator
+
+
+// ns3 includes
+#include "ns3/animation-interface.h"
+#include "ns3/netanim-config.h"
+#include "ns3/channel.h"
+#include "ns3/config.h"
+#include "ns3/node.h"
+#include "ns3/random-variable.h"
+#include "ns3/mobility-model.h"
+#include "ns3/packet.h"
+#include "ns3/simulator.h"
+#include "ns3/animation-interface-helper.h"
+#include "ns3/wifi-mac-header.h"
+#include "ns3/wimax-mac-header.h"
+
+#include <stdio.h>
+#include <sstream>
+#include <fstream>
+#include <string>
+#include <iomanip>
+#include <map>
+
+// Socket related includes
+#if defined(HAVE_SYS_SOCKET_H) && defined(HAVE_NETINET_IN_H)
+#include <sys/socket.h>
+#include <netinet/in.h>
+#else
+#include <fcntl.h>
+#endif
+
+NS_LOG_COMPONENT_DEFINE ("AnimationInterface");
+
+namespace ns3 {
+
+AnimationInterface::AnimationInterface ()
+ : m_fHandle (STDOUT_FILENO), m_xml (false), mobilitypollinterval (Seconds(0.25)),
+ usingSockets (false), mport (0), outputfilename (""),
+ OutputFileSet (false), ServerPortSet (false), gAnimUid (0),randomPosition (true),
+ m_writeCallback (0)
+{
+}
+
+AnimationInterface::AnimationInterface (const std::string fn, bool usingXML)
+ : m_fHandle (STDOUT_FILENO), m_xml (usingXML), mobilitypollinterval (Seconds(0.25)),
+ usingSockets (false), mport (0), outputfilename (fn),
+ OutputFileSet (false), ServerPortSet (false), gAnimUid (0), randomPosition (true),
+ m_writeCallback (0)
+{
+}
+
+AnimationInterface::AnimationInterface (const uint16_t port, bool usingXML)
+ : m_fHandle (STDOUT_FILENO), m_xml (usingXML), mobilitypollinterval (Seconds(0.25)),
+ usingSockets (true), mport (port), outputfilename (""),
+ OutputFileSet (false), ServerPortSet (false), gAnimUid (0), randomPosition (true),
+ m_writeCallback (0)
+{
+}
+
+AnimationInterface::~AnimationInterface ()
+{
+ StopAnimation ();
+}
+
+void AnimationInterface::SetXMLOutput ()
+{
+ NS_LOG_INFO ("XML output set");
+ m_xml = true;
+}
+
+bool AnimationInterface::SetOutputFile (const std::string& fn)
+{
+ if (OutputFileSet)
+ {
+ return true;
+ }
+ if (fn == "")
+ {
+ m_fHandle = STDOUT_FILENO;
+ OutputFileSet = true;
+ return true;
+ }
+ FILE* f = fopen (fn.c_str (), "w");
+ if (!f)
+ {
+ NS_FATAL_ERROR ("Unable to open Animation output file");
+ return false; // Can't open
+ }
+ m_fHandle = fileno (f); // Set the file handle
+ usingSockets = false;
+ outputfilename = fn;
+ OutputFileSet = true;
+ return true;
+}
+
+void AnimationInterface::SetAnimWriteCallback (AnimWriteCallback cb)
+{
+ m_writeCallback = cb;
+}
+
+void AnimationInterface::ResetAnimWriteCallback ()
+{
+ m_writeCallback = 0;
+}
+
+bool AnimationInterface::SetServerPort (uint16_t port)
+{
+#if defined(HAVE_SYS_SOCKET_H) && defined(HAVE_NETINET_IN_H)
+ if (ServerPortSet)
+ {
+ return true;
+ }
+ int s = socket (AF_INET, SOCK_STREAM, 0);
+ struct sockaddr_in addr;
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons (port);
+ addr.sin_addr.s_addr = htonl (INADDR_ANY);
+ if (bind (s, (struct sockaddr*)&addr, sizeof (addr)) < 0)
+ {
+ NS_LOG_WARN ("Can't bind to port " << port << ", exiting.");
+ return false;
+ }
+ listen (s, 1);
+ NS_LOG_INFO ("Waiting for animator connection");
+ // Now wait for the animator to connect in
+ m_fHandle = accept (s, 0, 0);
+ NS_LOG_INFO ("Got animator connection from remote");
+ // set the linger socket option
+ int t = 1;
+ setsockopt (s, SOL_SOCKET, SO_LINGER, &t, sizeof(t));
+ usingSockets = true;
+ ServerPortSet = true;
+ return true;
+#endif
+ return false; // never reached unless the above is disabled
+ // which is done to support a platform like MinGW
+}
+
+bool AnimationInterface::WifiPacketIsPending (uint64_t AnimUid)
+{
+ return (pendingWifiPackets.find (AnimUid) != pendingWifiPackets.end ());
+}
+
+bool AnimationInterface::CsmaPacketIsPending (uint64_t AnimUid)
+{
+ return (pendingCsmaPackets.find (AnimUid) != pendingCsmaPackets.end ());
+}
+
+
+bool AnimationInterface::WimaxPacketIsPending (uint64_t AnimUid)
+{
+ return (pendingWimaxPackets.find (AnimUid) != pendingWimaxPackets.end ());
+}
+
+void AnimationInterface::SetMobilityPollInterval (Time t)
+{
+ mobilitypollinterval = t;
+}
+
+void AnimationInterface::SetRandomPosition (bool setRandPos)
+{
+ randomPosition = setRandPos;
+}
+
+Vector AnimationInterface::UpdatePosition (Ptr <Node> n)
+{
+ Ptr<MobilityModel> loc = n->GetObject<MobilityModel> ();
+ if (loc)
+ {
+ nodeLocation[n->GetId ()] = loc->GetPosition ();
+ }
+ else
+ {
+ NS_LOG_WARN ( "Node:" << n->GetId () << " Does not have a mobility model");
+ Vector deterministicVector (100,100,0);
+ Vector randomVector (UniformVariable (0, topo_maxX-topo_minX).GetValue (), UniformVariable (0, topo_maxY-topo_minY).GetValue (), 0);
+ if (randomPosition)
+ {
+ nodeLocation[n->GetId ()] = randomVector;
+ }
+ else
+ {
+ nodeLocation[n->GetId ()] = deterministicVector;
+ }
+ }
+ return nodeLocation[n->GetId ()];
+}
+
+Vector AnimationInterface::UpdatePosition (Ptr <Node> n, Vector v)
+{
+ nodeLocation[n->GetId ()] = v;
+ return v;
+}
+
+Vector AnimationInterface::GetPosition (Ptr <Node> n)
+{
+ #ifdef NS_LOG
+ if (nodeLocation.find (n->GetId()) == nodeLocation.end ())
+ {
+ NS_FATAL_ERROR ("Node:" <<n->GetId() << " not found in Location table");
+ }
+ #endif
+ return nodeLocation[n->GetId ()];
+}
+
+void AnimationInterface::StartAnimation ()
+{
+ if (usingSockets)
+ {
+ SetServerPort (mport);
+ }
+ else
+ {
+ SetOutputFile (outputfilename);
+ }
+
+ // Find the min/max x/y for the xml topology element
+ topo_minX = -2;
+ topo_minY = -2;
+ topo_maxX = 2;
+ topo_maxY = 2;
+ for (NodeList::Iterator i = NodeList::Begin (); i != NodeList::End (); ++i)
+ {
+ Ptr<Node> n = *i;
+ NS_LOG_INFO ("Update Position for Node: " << n->GetId ());
+ Vector v = UpdatePosition (n);
+ topo_minX = std::min (topo_minX, v.x);
+ topo_minY = std::min (topo_minY, v.y);
+ topo_maxX = std::max (topo_maxX, v.x);
+ topo_maxY = std::max (topo_maxY, v.y);
+ }
+
+ AddMargin ();
+ if (m_xml)
+ { // output the xml headers
+ std::ostringstream oss;
+ oss << GetXMLOpen_anim (0);
+ oss << GetPreamble ();
+ oss << GetXMLOpen_topology (topo_minX,topo_minY,topo_maxX,topo_maxY);
+ WriteN (m_fHandle, oss.str ());
+ }
+ NS_LOG_INFO ("Setting topology for "<<NodeList::GetNNodes ()<<" Nodes");
+ // Dump the topology
+ for (NodeList::Iterator i = NodeList::Begin (); i != NodeList::End (); ++i)
+ {
+ Ptr<Node> n = *i;
+ std::ostringstream oss;
+ if (m_xml)
+ {
+ Vector v = GetPosition (n);
+ oss << GetXMLOpenClose_node (0,n->GetId (),v.x,v.y);
+ WriteN (m_fHandle, oss.str ());
+ }
+ else
+ {
+ // Location exists, dump it
+ Vector v = GetPosition (n);
+ oss << "0.0 N " << n->GetId ()
+ << " " << v.x << " " << v.y << std::endl;
+ WriteN (m_fHandle, oss.str ().c_str (), oss.str ().length ());
+ }
+ }
+ NS_LOG_INFO ("Setting p2p links");
+ // Now dump the p2p links
+ for (NodeList::Iterator i = NodeList::Begin (); i != NodeList::End (); ++i)
+ {
+ Ptr<Node> n = *i;
+ uint32_t n1Id = n->GetId ();
+ uint32_t nDev = n->GetNDevices (); // Number of devices
+ for (uint32_t i = 0; i < nDev; ++i)
+ {
+ Ptr<NetDevice> dev = n->GetDevice (i);
+ NS_ASSERT (dev);
+ Ptr<Channel> ch = dev->GetChannel ();
+ if (!ch)
+ {
+ NS_LOG_DEBUG ("No channel can't be a p2p device");
+ continue;
+ }
+ std::string channelType = ch->GetInstanceTypeId ().GetName ();
+ if (channelType == std::string ("ns3::PointToPointChannel"))
+ { // Since these are duplex links, we only need to dump
+ // if srcid < dstid
+ uint32_t nChDev = ch->GetNDevices ();
+ for (uint32_t j = 0; j < nChDev; ++j)
+ {
+ Ptr<NetDevice> chDev = ch->GetDevice (j);
+ uint32_t n2Id = chDev->GetNode ()->GetId ();
+ if (n1Id < n2Id)
+ { // ouptut the p2p link
+ std::ostringstream oss;
+ if (m_xml)
+ {
+ oss << GetXMLOpenClose_link (0,n1Id,0,n2Id);
+ }
+ else
+ {
+ oss << "0.0 L " << n1Id << " " << n2Id << std::endl;
+ }
+ WriteN (m_fHandle, oss.str ());
+ }
+ }
+ }
+ else
+ {
+ //NS_FATAL_ERROR ("Net animation currently only supports point-to-point links.");
+ }
+ }
+ }
+ if (m_xml)
+ {
+ WriteN (m_fHandle, GetXMLClose ("topology"));
+ Simulator::Schedule (mobilitypollinterval, &AnimationInterface::MobilityAutoCheck, this);
+ }
+
+ // Connect the callbacks
+ Config::Connect ("/ChannelList/*/TxRxPointToPoint",
+ MakeCallback (&AnimationInterface::DevTxTrace, this));
+ Config::Connect ("NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phy/PhyTxBegin",
+ MakeCallback (&AnimationInterface::WifiPhyTxBeginTrace, this));
+ Config::Connect ("NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phy/PhyTxEnd",
+ MakeCallback (&AnimationInterface::WifiPhyTxEndTrace, this));
+ Config::Connect ("NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phy/PhyRxBegin",
+ MakeCallback (&AnimationInterface::WifiPhyRxBeginTrace, this));
+ Config::Connect ("NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phy/PhyRxEnd",
+ MakeCallback (&AnimationInterface::WifiPhyRxEndTrace, this));
+ Config::Connect ("NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Mac/MacRx",
+ MakeCallback (&AnimationInterface::WifiMacRxTrace, this));
+ Config::ConnectWithoutContext ("/NodeList/*/$ns3::MobilityModel/CourseChange",
+ MakeCallback (&AnimationInterface::MobilityCourseChangeTrace, this));
+ Config::Connect ("/NodeList/*/DeviceList/*/$ns3::WimaxNetDevice/Tx",
+ MakeCallback (&AnimationInterface::WimaxTxTrace, this));
+ Config::Connect ("/NodeList/*/DeviceList/*/$ns3::WimaxNetDevice/Rx",
+ MakeCallback (&AnimationInterface::WimaxRxTrace, this));
+ Config::Connect ("/NodeList/*/DeviceList/*/$ns3::CsmaNetDevice/PhyTxBegin",
+ MakeCallback (&AnimationInterface::CsmaPhyTxBeginTrace, this));
+ Config::Connect ("/NodeList/*/DeviceList/*/$ns3::CsmaNetDevice/PhyTxEnd",
+ MakeCallback (&AnimationInterface::CsmaPhyTxEndTrace, this));
+ Config::Connect ("/NodeList/*/DeviceList/*/$ns3::CsmaNetDevice/PhyRxEnd",
+ MakeCallback (&AnimationInterface::CsmaPhyRxEndTrace, this));
+ Config::Connect ("/NodeList/*/DeviceList/*/$ns3::CsmaNetDevice/MacRx",
+ MakeCallback (&AnimationInterface::CsmaMacRxTrace, this));
+
+
+
+}
+
+void AnimationInterface::StopAnimation ()
+{
+ NS_LOG_INFO ("Stopping Animation");
+ if (m_fHandle > 0)
+ {
+ if (m_xml)
+ { // Terminate the anim element
+ WriteN (m_fHandle, GetXMLClose ("anim"));
+ }
+ if (m_fHandle != STDOUT_FILENO)
+ {
+ close (m_fHandle);
+ }
+ OutputFileSet = false;
+ m_fHandle = -1;
+ }
+}
+
+int AnimationInterface::WriteN (int h, const std::string& st)
+{
+ if (h < 0)
+ {
+ return 0;
+ }
+ if (m_writeCallback)
+ {
+ m_writeCallback (st.c_str ());
+ }
+ return WriteN (h, st.c_str (), st.length ());
+}
+
+
+// Private methods
+void AnimationInterface::AddMargin ()
+{
+ // Compute width/height, and add a small margin
+ double w = topo_maxX - topo_minX;
+ double h = topo_maxY - topo_minY;
+ topo_minX -= w * 0.05;
+ topo_minY -= h * 0.05;
+ topo_maxX = topo_minX + w * 1.5;
+ topo_maxY = topo_minY + h * 1.5;
+ NS_LOG_INFO ("Added Canvas Margin:" << topo_minX << "," <<
+ topo_minY << "," << topo_maxX << "," << topo_maxY);
+}
+
+std::vector <Ptr <Node> > AnimationInterface::RecalcTopoBounds ()
+{
+ std::vector < Ptr <Node> > MovedNodes;
+ for (NodeList::Iterator i = NodeList::Begin (); i != NodeList::End (); ++i)
+ {
+ Ptr<Node> n = *i;
+ NS_ASSERT (n);
+ Ptr <MobilityModel> mobility = n->GetObject <MobilityModel> ();
+ Vector newLocation;
+ if (!mobility)
+ {
+ newLocation = GetPosition (n);
+ }
+ else
+ {
+ newLocation = mobility->GetPosition ();
+ }
+ if (!NodeHasMoved (n, newLocation))
+ {
+ continue; //Location has not changed
+ }
+ else
+ {
+ UpdatePosition (n, newLocation);
+ RecalcTopoBounds (newLocation);
+ MovedNodes.push_back (n);
+ }
+ }
+ return MovedNodes;
+}
+
+void AnimationInterface::RecalcTopoBounds (Vector v)
+{
+ double oldminX = topo_minX;
+ double oldminY = topo_minY;
+ double oldmaxX = topo_maxX;
+ double oldmaxY = topo_maxY;
+ topo_minX = std::min (topo_minX, v.x);
+ topo_minY = std::min (topo_minY, v.y);
+ topo_maxX = std::max (topo_maxX, v.x);
+ topo_maxY = std::max (topo_maxY, v.y);
+
+ if ((topo_minX != oldminX) || (topo_minY != oldminY) ||
+ (topo_maxX != oldmaxX) || (topo_maxY != oldmaxY))
+ {
+ AddMargin ();
+ }
+}
+
+int AnimationInterface::WriteN (int h, const char* data, uint32_t count)
+{
+ if (h < 0)
+ {
+ return 0;
+ }
+ // Write count bytes to h from data
+ uint32_t nLeft = count;
+ const char* p = data;
+ uint32_t written = 0;
+ while (nLeft)
+ {
+ int n = write (h, p, nLeft);
+ if (n <= 0)
+ {
+ return written;
+ }
+ written += n;
+ nLeft -= n;
+ p += n;
+ }
+ return written;
+}
+
+void AnimationInterface::WriteDummyPacket ()
+{
+ Time now = Simulator::Now ();
+ std::ostringstream oss;
+ double fbTx = now.GetSeconds ();
+ double lbTx = now.GetSeconds ();
+ double fbRx = now.GetSeconds ();
+ double lbRx = now.GetSeconds ();
+ if (m_xml)
+ {
+ oss << GetXMLOpen_packet (0,0,fbTx,lbTx,"DummyPktIgnoreThis");
+ oss << GetXMLOpenClose_rx (0,0,fbRx,lbRx);
+ oss << GetXMLClose ("packet");
+ }
+ WriteN (m_fHandle, oss.str ());
+
+
+}
+void AnimationInterface::DevTxTrace (std::string context, Ptr<const Packet> p,
+ Ptr<NetDevice> tx, Ptr<NetDevice> rx,
+ Time txTime, Time rxTime)
+{
+ NS_ASSERT (tx);
+ NS_ASSERT (rx);
+ Time now = Simulator::Now ();
+ std::ostringstream oss;
+ double fbTx = now.GetSeconds ();
+ double lbTx = (now + txTime).GetSeconds ();
+ double fbRx = (now + rxTime - txTime).GetSeconds ();
+ double lbRx = (now + rxTime).GetSeconds ();
+ if (m_xml)
+ {
+ oss << GetXMLOpen_packet (0,tx->GetNode ()->GetId (),fbTx,lbTx);
+ oss << GetXMLOpenClose_rx (0,rx->GetNode ()->GetId (),fbRx,lbRx);
+ oss << GetXMLClose ("packet");
+ }
+ else
+ {
+ oss << std::setprecision (10);
+ oss << now.GetSeconds () << " P "
+ << tx->GetNode ()->GetId () << " "
+ << rx->GetNode ()->GetId () << " "
+ << (now + txTime).GetSeconds () << " " // last bit tx time
+ << (now + rxTime - txTime).GetSeconds () << " " // first bit rx time
+ << (now + rxTime).GetSeconds () << std::endl; // last bit rx time
+ }
+ WriteN (m_fHandle, oss.str ());
+}
+
+
+Ptr <NetDevice>
+AnimationInterface::GetNetDeviceFromContext (std::string context)
+{
+ // Use "NodeList/*/DeviceList/*/ as reference
+ // where element [1] is the Node Id
+ // element [2] is the NetDevice Id
+
+ std::vector <std::string> elements = GetElementsFromContext (context);
+ Ptr <Node> n = NodeList::GetNode (atoi (elements[1].c_str ()));
+ NS_ASSERT (n);
+ return n->GetDevice (atoi (elements[3].c_str ()));
+}
+
+void AnimationInterface::AddPendingWifiPacket (uint64_t AnimUid, AnimPacketInfo &pktinfo)
+{
+ NS_ASSERT (pktinfo.m_txnd);
+ pendingWifiPackets[AnimUid] = pktinfo;
+}
+
+void AnimationInterface::AddPendingWimaxPacket (uint64_t AnimUid, AnimPacketInfo &pktinfo)
+{
+ NS_ASSERT (pktinfo.m_txnd);
+ pendingWimaxPackets[AnimUid] = pktinfo;
+}
+
+
+void AnimationInterface::AddPendingCsmaPacket (uint64_t AnimUid, AnimPacketInfo &pktinfo)
+{
+ NS_ASSERT (pktinfo.m_txnd);
+ pendingCsmaPackets[AnimUid] = pktinfo;
+}
+
+uint64_t AnimationInterface::GetAnimUidFromPacket (Ptr <const Packet> p)
+{
+ AnimByteTag tag;
+ if (p->FindFirstMatchingByteTag (tag))
+ {
+ return tag.Get ();
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+void AnimationInterface::WifiPhyTxBeginTrace (std::string context,
+ Ptr<const Packet> p)
+{
+ Ptr <NetDevice> ndev = GetNetDeviceFromContext (context);
+ NS_ASSERT (ndev);
+ Ptr <Node> n = ndev->GetNode ();
+ NS_ASSERT (n);
+ // Add a new pending wireless
+ gAnimUid++;
+ NS_LOG_INFO ("TxBeginTrace for packet:" << gAnimUid);
+ AnimByteTag tag;
+ tag.Set (gAnimUid);
+ p->AddByteTag (tag);
+ AnimPacketInfo pktinfo (ndev, Simulator::Now (), Simulator::Now (), UpdatePosition (n));
+ AddPendingWifiPacket (gAnimUid, pktinfo);
+}
+
+void AnimationInterface::WifiPhyTxEndTrace (std::string context,
+ Ptr<const Packet> p)
+{
+}
+
+void AnimationInterface::WifiPhyTxDropTrace (std::string context,
+ Ptr<const Packet> p)
+{
+ Ptr <NetDevice> ndev = GetNetDeviceFromContext (context);
+ NS_ASSERT (ndev);
+ // Erase pending wifi
+ uint64_t AnimUid = GetAnimUidFromPacket (p);
+ NS_LOG_INFO ("TxDropTrace for packet:" << AnimUid);
+ NS_ASSERT (WifiPacketIsPending (AnimUid) == true);
+ pendingWifiPackets.erase (pendingWifiPackets.find (AnimUid));
+}
+
+
+void AnimationInterface::WifiPhyRxBeginTrace (std::string context,
+ Ptr<const Packet> p)
+{
+ Ptr <NetDevice> ndev = GetNetDeviceFromContext (context);
+ NS_ASSERT (ndev);
+ uint64_t AnimUid = GetAnimUidFromPacket (p);
+ NS_LOG_INFO ("RxBeginTrace for packet:" << AnimUid);
+ if (!WifiPacketIsPending (AnimUid))
+ {
+ NS_LOG_WARN ("WifiPhyRxBeginTrace: unknown Uid");
+ return;
+ }
+ // TODO: NS_ASSERT (WifiPacketIsPending (AnimUid) == true);
+ pendingWifiPackets[AnimUid].ProcessRxBegin (ndev, Simulator::Now ());
+}
+
+
+void AnimationInterface::WifiPhyRxEndTrace (std::string context,
+ Ptr<const Packet> p)
+{
+ Ptr <NetDevice> ndev = GetNetDeviceFromContext (context);
+ NS_ASSERT (ndev);
+ Ptr <Node> n = ndev->GetNode ();
+ NS_ASSERT (n);
+ uint64_t AnimUid = GetAnimUidFromPacket (p);
+ if (!WifiPacketIsPending (AnimUid))
+ {
+ NS_LOG_WARN ("WifiPhyRxEndTrace: unknown Uid");
+ return;
+ }
+ // TODO: NS_ASSERT (WifiPacketIsPending (AnimUid) == true);
+ AnimPacketInfo& pktInfo = pendingWifiPackets[AnimUid];
+ pktInfo.ProcessRxEnd (ndev, Simulator::Now (), UpdatePosition (n));
+}
+
+void AnimationInterface::WifiMacRxTrace (std::string context,
+ Ptr<const Packet> p)
+{
+ Ptr <NetDevice> ndev = GetNetDeviceFromContext (context);
+ NS_ASSERT (ndev);
+ Ptr <Node> n = ndev->GetNode ();
+ NS_ASSERT (n);
+ uint64_t AnimUid = GetAnimUidFromPacket (p);
+ if (!WifiPacketIsPending (AnimUid))
+ {
+ NS_LOG_WARN ("WifiMacRxTrace: unknown Uid");
+ return;
+ }
+ // TODO: NS_ASSERT (WifiPacketIsPending (AnimUid) == true);
+ AnimPacketInfo& pktInfo = pendingWifiPackets[AnimUid];
+ AnimRxInfo pktrxInfo = pktInfo.GetRxInfo (ndev);
+ if (pktrxInfo.IsPhyRxComplete ())
+ {
+ NS_LOG_INFO ("MacRxTrace for packet:" << AnimUid << " complete");
+ OutputWirelessPacket (pktInfo, pktrxInfo);
+ pktInfo.RemoveRxInfo (ndev);
+ }
+
+}
+void AnimationInterface::WifiPhyRxDropTrace (std::string context,
+ Ptr<const Packet> p)
+{
+}
+
+void AnimationInterface::WimaxTxTrace (std::string context, Ptr<const Packet> p, const Mac48Address & m)
+{
+ Ptr <NetDevice> ndev = GetNetDeviceFromContext (context);
+ NS_ASSERT (ndev);
+ Ptr <Node> n = ndev->GetNode ();
+ NS_ASSERT (n);
+ gAnimUid++;
+ NS_LOG_INFO ("WimaxTxTrace for packet:" << gAnimUid);
+ AnimPacketInfo pktinfo (ndev, Simulator::Now (), Simulator::Now () + Seconds (0.001), UpdatePosition (n));
+ //TODO 0.0001 is used until Wimax implements TxBegin and TxEnd traces
+ AnimByteTag tag;
+ tag.Set (gAnimUid);
+ p->AddByteTag (tag);
+ AddPendingWimaxPacket (gAnimUid, pktinfo);
+}
+
+
+void AnimationInterface::WimaxRxTrace (std::string context, Ptr<const Packet> p, const Mac48Address & m)
+{
+ Ptr <NetDevice> ndev = GetNetDeviceFromContext (context);
+ NS_ASSERT (ndev);
+ Ptr <Node> n = ndev->GetNode ();
+ NS_ASSERT (n);
+ uint64_t AnimUid = GetAnimUidFromPacket (p);
+ NS_ASSERT (WimaxPacketIsPending (AnimUid) == true);
+ AnimPacketInfo& pktInfo = pendingWimaxPackets[AnimUid];
+ pktInfo.ProcessRxBegin (ndev, Simulator::Now ());
+ pktInfo.ProcessRxEnd (ndev, Simulator::Now () + Seconds (0.001), UpdatePosition (n));
+ //TODO 0.001 is used until Wimax implements RxBegin and RxEnd traces
+ AnimRxInfo pktrxInfo = pktInfo.GetRxInfo (ndev);
+ OutputWirelessPacket (pktInfo, pktrxInfo);
+}
+
+void AnimationInterface::CsmaPhyTxBeginTrace (std::string context, Ptr<const Packet> p)
+{
+ Ptr <NetDevice> ndev = GetNetDeviceFromContext (context);
+ NS_ASSERT (ndev);
+ Ptr <Node> n = ndev->GetNode ();
+ NS_ASSERT (n);
+ gAnimUid++;
+ NS_LOG_INFO ("CsmaPhyTxBeginTrace for packet:" << gAnimUid);
+ AnimByteTag tag;
+ tag.Set (gAnimUid);
+ p->AddByteTag (tag);
+ AnimPacketInfo pktinfo (ndev, Simulator::Now (), Simulator::Now (), UpdatePosition (n));
+ AddPendingCsmaPacket (gAnimUid, pktinfo);
+
+}
+
+void AnimationInterface::CsmaPhyTxEndTrace (std::string context, Ptr<const Packet> p)
+{
+ Ptr <NetDevice> ndev = GetNetDeviceFromContext (context);
+ NS_ASSERT (ndev);
+ uint64_t AnimUid = GetAnimUidFromPacket (p);
+ NS_LOG_INFO ("CsmaPhyTxEndTrace for packet:" << AnimUid);
+ if (!CsmaPacketIsPending (AnimUid))
+ {
+ NS_LOG_WARN ("CsmaPhyTxEndTrace: unknown Uid");
+ return;
+ }
+ // TODO: NS_ASSERT (CsmaPacketIsPending (AnimUid) == true);
+ AnimPacketInfo& pktInfo = pendingCsmaPackets[AnimUid];
+ pktInfo.m_lbTx = Simulator::Now ().GetSeconds ();
+}
+
+void AnimationInterface::CsmaPhyRxEndTrace (std::string context, Ptr<const Packet> p)
+{
+ Ptr <NetDevice> ndev = GetNetDeviceFromContext (context);
+ NS_ASSERT (ndev);
+ Ptr <Node> n = ndev->GetNode ();
+ NS_ASSERT (n);
+ uint64_t AnimUid = GetAnimUidFromPacket (p);
+ if (!CsmaPacketIsPending (AnimUid))
+ {
+ NS_LOG_WARN ("CsmaPhyRxEndTrace: unknown Uid");
+ return;
+ }
+ // TODO: NS_ASSERT (CsmaPacketIsPending (AnimUid) == true);
+ AnimPacketInfo& pktInfo = pendingCsmaPackets[AnimUid];
+ pendingCsmaPackets[AnimUid].ProcessRxBegin (ndev, Simulator::Now ());
+ pktInfo.ProcessRxEnd (ndev, Simulator::Now (), UpdatePosition (n));
+ NS_LOG_INFO ("CsmaPhyRxEndTrace for packet:" << AnimUid);
+}
+
+
+void AnimationInterface::CsmaMacRxTrace (std::string context,
+ Ptr<const Packet> p)
+{
+ NS_LOG_FUNCTION (this);
+ Ptr <NetDevice> ndev = GetNetDeviceFromContext (context);
+ NS_ASSERT (ndev);
+ Ptr <Node> n = ndev->GetNode ();
+ NS_ASSERT (n);
+ uint64_t AnimUid = GetAnimUidFromPacket (p);
+ if (!CsmaPacketIsPending (AnimUid))
+ {
+ NS_LOG_WARN ("CsmaMacRxTrace: unknown Uid");
+ return;
+ }
+ // TODO: NS_ASSERT (CsmaPacketIsPending (AnimUid) == true);
+ AnimPacketInfo& pktInfo = pendingCsmaPackets[AnimUid];
+ AnimRxInfo pktrxInfo = pktInfo.GetRxInfo (ndev);
+ if (pktrxInfo.IsPhyRxComplete ())
+ {
+ NS_LOG_INFO ("MacRxTrace for packet:" << AnimUid << " complete");
+ OutputCsmaPacket (pktInfo, pktrxInfo);
+ pktInfo.RemoveRxInfo (ndev);
+ }
+}
+
+
+void AnimationInterface::MobilityCourseChangeTrace (Ptr <const MobilityModel> mobility)
+
+{
+ Ptr <Node> n = mobility->GetObject <Node> ();
+ NS_ASSERT (n);
+ Vector v ;
+ if (!mobility)
+ {
+ v = GetPosition (n);
+ }
+ else
+ {
+ v = mobility->GetPosition ();
+ }
+ UpdatePosition (n,v);
+ RecalcTopoBounds (v);
+ std::ostringstream oss;
+ oss << GetXMLOpen_topology (topo_minX,topo_minY,topo_maxX,topo_maxY);
+ oss << GetXMLOpenClose_node (0,n->GetId (),v.x,v.y);
+ oss << GetXMLClose ("topology");
+ WriteN (m_fHandle, oss.str ());
+ WriteDummyPacket ();
+}
+
+bool AnimationInterface::NodeHasMoved (Ptr <Node> n, Vector newLocation)
+{
+ Vector oldLocation = GetPosition (n);
+ if ((ceil(oldLocation.x) == ceil(newLocation.x)) &&
+ (ceil(oldLocation.y) == ceil(newLocation.y)))
+ {
+
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+}
+
+void AnimationInterface::MobilityAutoCheck ()
+{
+ std::vector <Ptr <Node> > MovedNodes = RecalcTopoBounds ();
+ std::ostringstream oss;
+ oss << GetXMLOpen_topology (topo_minX,topo_minY,topo_maxX,topo_maxY);
+ for (uint32_t i = 0; i < MovedNodes.size (); i++)
+ {
+ Ptr <Node> n = MovedNodes [i];
+ NS_ASSERT (n);
+ Vector v = GetPosition (n);
+ oss << GetXMLOpenClose_node (0,n->GetId (), v.x, v.y);
+ }
+ oss << GetXMLClose ("topology");
+ WriteN (m_fHandle, oss.str ());
+ WriteDummyPacket ();
+ if (!Simulator::IsFinished ())
+ {
+ Simulator::Schedule (mobilitypollinterval, &AnimationInterface::MobilityAutoCheck, this);
+ }
+}
+
+
+// Helper to output a wireless packet.
+// For now, only the XML interface is supported
+
+
+std::string AnimationInterface::GetPreamble ()
+{
+ std::string s =
+ "<information><!-- \n\
+ Description of attributes:\n\
+ =========================\n\
+ anim\n\
+ * lp = Logical Processor Id\n\
+ topology\n\
+ * minX = minimum X coordinate of the canvas\n\
+ * minY = minimum Y coordinate of the canvas\n\
+ * maxX = maximum X coordinate of the canvas\n\
+ * maxY = maximum Y coordinate of the canvas\n\
+ node\n\
+ * lp = Logical Processor Id\n\
+ * id = Node Id\n\
+ * locX = X coordinate\n\
+ * locY = Y coordinate\n\
+ link\n\
+ * fromLp = From logical processor Id\n\
+ * fromId = From Node Id\n\
+ * toLp = To logical processor Id\n\
+ * toId = To Node Id\n\
+ packet\n\
+ * fromLp = From logical processor Id\n\
+ * fbTx = First bit transmit time\n\
+ * lbTx = Last bit transmit time\n\
+ rx\n\
+ * toLp = To logical processor Id\n\
+ * toId = To Node Id\n\
+ * fbRx = First bit Rx Time\n\
+ * lbRx = Last bit Rx\n\
+ wpacket\n\
+ * fromLp = From logical processor Id\n\
+ * fromId = From Node Id\n\
+ * fbTx = First bit transmit time\n\
+ * lbTx = Last bit transmit time\n\
+ * range = Reception range\n\
+ rx\n\
+ * toLp = To logical processor Id\n\
+ * toId = To Node Id\n\
+ * fbRx = First bit Rx time\n\
+ * lbRx = Last bit Rx time-->\n\
+ </information>\n";
+return s;
+}
+
+void AnimationInterface::OutputWirelessPacket (AnimPacketInfo &pktInfo, AnimRxInfo pktrxInfo)
+{
+ NS_ASSERT (m_xml);
+ std::ostringstream oss;
+ NS_ASSERT (pktInfo.m_txnd);
+ uint32_t nodeId = pktInfo.m_txnd->GetNode ()->GetId ();
+
+ double lbTx = pktInfo.firstlastbitDelta + pktInfo.m_fbTx;
+ oss << GetXMLOpen_wpacket (0, nodeId, pktInfo.m_fbTx, lbTx, pktrxInfo.rxRange);
+
+ uint32_t rxId = pktrxInfo.m_rxnd->GetNode ()->GetId ();
+ oss << GetXMLOpenClose_rx (0, rxId, pktrxInfo.m_fbRx, pktrxInfo.m_lbRx);
+
+ oss << GetXMLClose ("wpacket");
+ WriteN (m_fHandle, oss.str ());
+}
+
+void AnimationInterface::OutputCsmaPacket (AnimPacketInfo &pktInfo, AnimRxInfo pktrxInfo)
+{
+ NS_ASSERT (m_xml);
+ std::ostringstream oss;
+ NS_ASSERT (pktInfo.m_txnd);
+ uint32_t nodeId = pktInfo.m_txnd->GetNode ()->GetId ();
+
+ oss << GetXMLOpen_packet (0, nodeId, pktInfo.m_fbTx, pktInfo.m_lbTx);
+ uint32_t rxId = pktrxInfo.m_rxnd->GetNode ()->GetId ();
+ oss << GetXMLOpenClose_rx (0, rxId, pktrxInfo.m_fbRx, pktrxInfo.m_lbRx);
+ oss << GetXMLClose ("packet");
+ WriteN (m_fHandle, oss.str ());
+}
+
+
+// XML Private Helpers
+
+std::string AnimationInterface::GetXMLOpen_anim (uint32_t lp)
+{
+ std::ostringstream oss;
+ oss <<"<anim lp = \"" << lp << "\" >\n";
+ return oss.str ();
+}
+std::string AnimationInterface::GetXMLOpen_topology (double minX,double minY,double maxX,double maxY)
+{
+ std::ostringstream oss;
+ oss << "<topology minX = \"" << minX << "\" minY = \"" << minY
+ << "\" maxX = \"" << maxX << "\" maxY = \"" << maxY
+ << "\">" << std::endl;
+ return oss.str ();
+
+}
+
+std::string AnimationInterface::GetXMLOpenClose_node (uint32_t lp,uint32_t id,double locX,double locY)
+{
+ std::ostringstream oss;
+ oss <<"<node lp = \"" << lp << "\" id = \"" << id << "\"" << " locX = \""
+ << locX << "\" " << "locY = \"" << locY << "\" />\n";
+ return oss.str ();
+}
+std::string AnimationInterface::GetXMLOpenClose_link (uint32_t fromLp,uint32_t fromId, uint32_t toLp, uint32_t toId)
+{
+ std::ostringstream oss;
+ oss << "<link fromLp=\"0\" fromId=\"" << fromId
+ << "\" toLp=\"0\" toId=\"" << toId
+ << "\"/>" << std::endl;
+ return oss.str ();
+}
+
+
+std::string AnimationInterface::GetXMLOpen_packet (uint32_t fromLp,uint32_t fromId, double fbTx, double lbTx, std::string auxInfo)
+{
+ std::ostringstream oss;
+ oss << std::setprecision (10);
+ oss << "<packet fromLp=\"" << fromLp << "\" fromId=\"" << fromId
+ << "\" fbTx=\"" << fbTx
+ << "\" lbTx=\"" << lbTx
+ << (auxInfo.empty()?"":"\" aux=\"") << auxInfo.c_str ()
+ << "\">";
+ return oss.str ();
+}
+
+std::string AnimationInterface::GetXMLOpen_wpacket (uint32_t fromLp,uint32_t fromId, double fbTx, double lbTx, double range)
+{
+ std::ostringstream oss;
+ oss << std::setprecision (10);
+ oss << "<wpacket fromLp = \"" << fromLp << "\" fromId = \"" << fromId
+ << "\" fbTx = \"" << fbTx
+ << "\" lbTx = \"" << lbTx
+ << "\" range = \"" << range << "\">" << std::endl;
+ return oss.str ();
+
+}
+
+std::string AnimationInterface::GetXMLOpenClose_rx (uint32_t toLp, uint32_t toId, double fbRx, double lbRx)
+{
+ std::ostringstream oss;
+ oss << std::setprecision (10);
+ oss << "<rx toLp=\"" << toLp <<"\" toId=\"" << toId
+ << "\" fbRx=\"" << fbRx
+ << "\" lbRx=\"" << lbRx
+ << "\"/>" << std::endl;
+ return oss.str ();
+}
+
+std::vector<std::string> AnimationInterface::GetElementsFromContext (std::string context)
+{
+ std::vector <std::string> elements;
+ size_t pos1=0, pos2;
+ while (pos1 != context.npos)
+ {
+ pos1 = context.find ("/",pos1);
+ pos2 = context.find ("/",pos1+1);
+ elements.push_back (context.substr (pos1+1,pos2-(pos1+1)));
+ pos1 = pos2;
+ pos2 = context.npos;
+ }
+ return elements;
+}
+
+TypeId
+AnimByteTag::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::AnimByteTag")
+ .SetParent<Tag> ()
+ .AddConstructor<AnimByteTag> ()
+ ;
+ return tid;
+}
+TypeId
+AnimByteTag::GetInstanceTypeId (void) const
+{
+ return GetTypeId ();
+}
+
+uint32_t
+AnimByteTag::GetSerializedSize (void) const
+{
+ return sizeof (uint64_t);
+}
+void
+AnimByteTag::Serialize (TagBuffer i) const
+{
+ i.WriteU64 (m_AnimUid);
+}
+void
+AnimByteTag::Deserialize (TagBuffer i)
+{
+ m_AnimUid = i.ReadU64 ();
+}
+void
+AnimByteTag::Print (std::ostream &os) const
+{
+ os << "AnimUid=" << m_AnimUid;
+}
+void
+AnimByteTag::Set (uint64_t AnimUid)
+{
+ m_AnimUid = AnimUid;
+}
+
+uint64_t
+AnimByteTag::Get (void) const
+{
+ return m_AnimUid;
+}
+
+
+} // namespace ns3
--- a/src/netanim/model/canvas-location.cc Sat Aug 20 14:41:19 2011 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +0,0 @@
-/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2009 Georgia Institute of Technology
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: George Riley<riley@ece.gatech.edu>
- */
-
-#include "canvas-location.h"
-
-namespace ns3 {
-
-NS_OBJECT_ENSURE_REGISTERED (CanvasLocation);
-
-TypeId
-CanvasLocation::GetTypeId (void)
-{
- static TypeId tid = TypeId ("ns3::CanvasLocation")
- .SetParent<Object> ()
- .AddAttribute ("Location", "The current location on the canvas.",
- TypeId::ATTR_SET | TypeId::ATTR_GET,
- VectorValue (Vector (0.0, 0.0, 0.0)),
- MakeVectorAccessor (&CanvasLocation::SetLocation,
- &CanvasLocation::GetLocation),
- MakeVectorChecker ())
- ;
- return tid;
-}
-
-CanvasLocation::CanvasLocation ()
-{
-}
-
-CanvasLocation::~CanvasLocation ()
-{
-}
-
-Vector
-CanvasLocation::GetLocation (void) const
-{
- return m_location;
-}
-
-void
-CanvasLocation::SetLocation (const Vector &location)
-{
- m_location = location;
-}
-
-} // namespace ns3
--- a/src/netanim/model/canvas-location.h Sat Aug 20 14:41:19 2011 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,64 +0,0 @@
-/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2009 Georgia Institute of Technology
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: George Riley<riley@ece.gatech.edu>
- */
-#ifndef CANVAS_LOCATION_H
-#define CANVAS_LOCATION_H
-
-#include "ns3/object.h"
-#include "ns3/traced-callback.h"
-#include "ns3/vector.h"
-
-namespace ns3 {
-
-
-/**
- * \ingroup netanim
- *
- * \brief Keep track of the current location of an object
- *
- * This can be used anytime a logical node location is needed
- * (as opposed to a physical location used by the wireless PHY
- * layer to calculate path loss). One potential use of
- * this is by the animator to determine where to position the
- * node icon on the animation display. Location units are
- * arbitrary and dimensionless. In the case of use by the
- * animator they dimensions are in pixels.
- */
-class CanvasLocation : public Object
-{
-public:
- static TypeId GetTypeId (void);
- CanvasLocation ();
- virtual ~CanvasLocation ();
-
- /**
- * \returns the current location
- */
- Vector GetLocation (void) const;
- /**
- * \param location the location to set.
- */
- void SetLocation (const Vector &location);
-private:
- Vector m_location;
-};
-
-}; // namespace ns3
-
-#endif /* CANVAS_LOCATION_H */
--- a/src/netanim/wscript Sat Aug 20 14:41:19 2011 -0400
+++ b/src/netanim/wscript Mon Oct 17 16:59:17 2011 -0400
@@ -1,14 +1,14 @@
## -*-Mode : python; py-indent-offset : 4; indent-tabs-mode : nil; coding : utf-8; -*-
def build (bld) :
- module = bld.create_ns3_module ('netanim', ['internet', 'mobility', 'wimax', 'wifi'])
+ module = bld.create_ns3_module ('netanim', ['internet', 'mobility', 'wimax', 'wifi', 'csma'])
module.includes = '.'
module.source = [
'model/animation-interface.cc',
'helper/animation-interface-helper.cc',
]
- headers = bld.new_task_gen ('ns3header')
+ headers = bld.new_task_gen (features=['ns3header'])
headers.module = 'netanim'
headers.source = [
'model/animation-interface.h',
--- a/src/network/model/node.h Sat Aug 20 14:41:19 2011 -0400
+++ b/src/network/model/node.h Mon Oct 17 16:59:17 2011 -0400
@@ -111,9 +111,7 @@
* \returns the index of the Application within the Node's list
* of Application.
*
- * Associated this Application to this Node. This method is called
- * automatically from Application::Application so the user
- * has little reasons to call this method directly.
+ * Associated this Application to this Node.
*/
uint32_t AddApplication (Ptr<Application> application);
/**
--- a/src/network/wscript Sat Aug 20 14:41:19 2011 -0400
+++ b/src/network/wscript Mon Oct 17 16:59:17 2011 -0400
@@ -67,7 +67,7 @@
'test/sequence-number-test-suite.cc',
]
- headers = bld.new_task_gen('ns3header')
+ headers = bld.new_task_gen(features=['ns3header'])
headers.module = 'network'
headers.source = [
'model/address.h',
--- a/src/nix-vector-routing/wscript Sat Aug 20 14:41:19 2011 -0400
+++ b/src/nix-vector-routing/wscript Mon Oct 17 16:59:17 2011 -0400
@@ -8,7 +8,7 @@
'helper/ipv4-nix-vector-helper.cc',
]
- headers = bld.new_task_gen('ns3header')
+ headers = bld.new_task_gen(features=['ns3header'])
headers.module = 'nix-vector-routing'
headers.source = [
'model/ipv4-nix-vector-routing.h',
--- a/src/olsr/wscript Sat Aug 20 14:41:19 2011 -0400
+++ b/src/olsr/wscript Mon Oct 17 16:59:17 2011 -0400
@@ -20,7 +20,7 @@
'test/tc-regression-test.cc',
]
- headers = bld.new_task_gen('ns3header')
+ headers = bld.new_task_gen(features=['ns3header'])
headers.module = 'olsr'
headers.source = [
'model/olsr-routing-protocol.h',
--- a/src/openflow/wscript Sat Aug 20 14:41:19 2011 -0400
+++ b/src/openflow/wscript Mon Oct 17 16:59:17 2011 -0400
@@ -2,27 +2,24 @@
import os
import Options
+from waflib.Errors import WafError
-def set_options(opt):
+def options(opt):
opt.add_option('--with-openflow',
help=('Path to OFSID source for NS-3 OpenFlow Integration support'),
default='', dest='with_openflow')
- opt.tool_options('boost')
+ opt.tool_options('boost', tooldir=["waf-tools"])
def configure(conf):
- conf.check_tool('boost')
- conf.env['BOOST'] = conf.check_boost(lib = 'signals filesystem',
- kind = 'STATIC_BOTH',
- score_version = (-1000, 1000),
- tag_minscore = 1000)
- if not conf.env['BOOST']:
- conf.env['BOOST'] = conf.check_boost(lib = 'signals filesystem',
- kind = 'STATIC_BOTH',
- score_version = (-1000, 1000),
- tag_minscore = 1000,
- libpath="/usr/lib64")
+ try:
+ conf.check_tool('boost')
+ conf.check_boost(lib='signals filesystem')
+ if not conf.env.LIB_BOOST:
+ conf.check_boost(lib='signals filesystem', libpath="/usr/lib64")
+ except WafError:
+ conf.env['LIB_BOOST'] = []
- if not conf.env['BOOST']:
+ if not conf.env.LIB_BOOST:
conf.report_optional_feature("openflow", "NS-3 OpenFlow Integration", False,
"Required boost libraries not found")
@@ -34,16 +31,16 @@
if Options.options.with_openflow:
if os.path.isdir(Options.options.with_openflow):
- conf.check_message("OpenFlow location", '', True, ("%s (given)" % Options.options.with_openflow))
+ conf.msg("Checking for OpenFlow location", ("%s (given)" % Options.options.with_openflow))
conf.env['WITH_OPENFLOW'] = os.path.abspath(Options.options.with_openflow)
else:
openflow_dir = os.path.join('..','openflow')
if os.path.isdir(openflow_dir):
- conf.check_message("OpenFlow location", '', True, ("%s (guessed)" % openflow_dir))
+ conf.msg("Checking for OpenFlow location", ("%s (guessed)" % openflow_dir))
conf.env['WITH_OPENFLOW'] = os.path.abspath(openflow_dir)
del openflow_dir
if not conf.env['WITH_OPENFLOW']:
- conf.check_message("OpenFlow location", '', False)
+ conf.msg("Checking for OpenFlow location", False)
conf.report_optional_feature("openflow", "NS-3 OpenFlow Integration", False,
"OpenFlow not enabled (see option --with-openflow)")
# Add this module to the list of modules that won't be built
@@ -99,28 +96,24 @@
}
'''
- conf.env['DL'] = conf.check(mandatory=True, lib='dl', define_name='DL', uselib='DL')
- conf.env['XML2'] = conf.check(mandatory=True, lib='xml2', define_name='XML2', uselib='XML2')
+ conf.env['DL'] = conf.check(mandatory=True, lib='dl', define_name='DL', uselib_store='DL')
+ conf.env['XML2'] = conf.check(mandatory=True, lib='xml2', define_name='XML2', uselib_store='XML2')
conf.env.append_value('NS3_MODULE_PATH',os.path.abspath(os.path.join(conf.env['WITH_OPENFLOW'],'build','default')))
- conf.env['CPPPATH_OPENFLOW'] = [
+ conf.env['INCLUDES_OPENFLOW'] = [
os.path.abspath(os.path.join(conf.env['WITH_OPENFLOW'],'include'))]
conf.env['LIBPATH_OPENFLOW'] = [
os.path.abspath(os.path.join(conf.env['WITH_OPENFLOW'],'build','default')),
os.path.abspath(os.path.join(conf.env['WITH_OPENFLOW'],'lib'))]
- conf.env['OPENFLOW'] = conf.check(fragment=test_code, lib='openflow',
- libpath=conf.env['LIBPATH_OPENFLOW'],
- uselib='OPENFLOW DL XML2')
-
+ conf.env['OPENFLOW'] = conf.check_nonfatal(fragment=test_code, lib='openflow',
+ libpath=conf.env['LIBPATH_OPENFLOW'],
+ use='OPENFLOW DL XML2')
conf.report_optional_feature("openflow", "NS-3 OpenFlow Integration",
conf.env['OPENFLOW'], "openflow library not found")
if conf.env['OPENFLOW']:
conf.env['ENABLE_OPENFLOW'] = True
- conf.env.append_value('CXXDEFINES', 'NS3_OPENFLOW')
- conf.env.append_value('CPPPATH', conf.env['CPPPATH_OPENFLOW'])
- conf.env.append_value('LIBPATH', conf.env['LIBPATH_OPENFLOW'])
else:
# Add this module to the list of modules that won't be built
# if they are enabled.
@@ -143,10 +136,10 @@
]
if bld.env['OPENFLOW'] and bld.env['DL'] and bld.env['XML2']:
- obj.uselib = 'OPENFLOW DL XML2'
- obj_test.uselib = 'OPENFLOW DL XML2'
+ obj.use.extend('OPENFLOW DL XML2'.split())
+ obj_test.use.extend('OPENFLOW DL XML2'.split())
- headers = bld.new_task_gen('ns3header')
+ headers = bld.new_task_gen(features=['ns3header'])
headers.module = 'openflow'
headers.source = [
]
@@ -155,6 +148,10 @@
obj.source.append('model/openflow-interface.cc')
obj.source.append('model/openflow-switch-net-device.cc')
obj.source.append('helper/openflow-switch-helper.cc')
+
+ obj.env.append_value('DEFINES', 'NS3_OPENFLOW')
+ obj.use.append("OPENFLOW")
+
obj_test.source.append('test/openflow-switch-test-suite.cc')
headers.source.append('model/openflow-interface.h')
headers.source.append('model/openflow-switch-net-device.h')
--- a/src/point-to-point-layout/wscript Sat Aug 20 14:41:19 2011 -0400
+++ b/src/point-to-point-layout/wscript Mon Oct 17 16:59:17 2011 -0400
@@ -9,7 +9,7 @@
'model/point-to-point-star.cc',
]
- headers = bld.new_task_gen('ns3header')
+ headers = bld.new_task_gen(features=['ns3header'])
headers.module = 'point-to-point-layout'
headers.source = [
'model/point-to-point-dumbbell.h',
--- a/src/point-to-point/wscript Sat Aug 20 14:41:19 2011 -0400
+++ b/src/point-to-point/wscript Mon Oct 17 16:59:17 2011 -0400
@@ -16,7 +16,7 @@
'test/point-to-point-test.cc',
]
- headers = bld.new_task_gen('ns3header')
+ headers = bld.new_task_gen(features=['ns3header'])
headers.module = 'point-to-point'
headers.source = [
'model/point-to-point-net-device.h',
--- a/src/propagation/wscript Sat Aug 20 14:41:19 2011 -0400
+++ b/src/propagation/wscript Mon Oct 17 16:59:17 2011 -0400
@@ -15,7 +15,7 @@
'test/propagation-loss-model-test-suite.cc',
]
- headers = bld.new_task_gen('ns3header')
+ headers = bld.new_task_gen(features=['ns3header'])
headers.module = 'propagation'
headers.source = [
'model/propagation-delay-model.h',
--- a/src/spectrum/bindings/callbacks_list.py Sat Aug 20 14:41:19 2011 -0400
+++ b/src/spectrum/bindings/callbacks_list.py Mon Oct 17 16:59:17 2011 -0400
@@ -1,7 +1,7 @@
callback_classes = [
+ ['void', 'ns3::Ptr<ns3::Packet const>', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty'],
['void', 'ns3::Ptr<ns3::Packet>', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty'],
['void', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty'],
- ['void', 'ns3::Ptr<ns3::Packet const>', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty'],
['bool', 'ns3::Ptr<ns3::Packet>', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty'],
['bool', 'ns3::Ptr<ns3::NetDevice>', 'ns3::Ptr<ns3::Packet const>', 'unsigned short', 'ns3::Address const&', 'ns3::Address const&', 'ns3::NetDevice::PacketType', 'ns3::empty', 'ns3::empty', 'ns3::empty'],
['bool', 'ns3::Ptr<ns3::NetDevice>', 'ns3::Ptr<ns3::Packet const>', 'unsigned short', 'ns3::Address const&', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty'],
--- a/src/spectrum/bindings/modulegen__gcc_ILP32.py Sat Aug 20 14:41:19 2011 -0400
+++ b/src/spectrum/bindings/modulegen__gcc_ILP32.py Mon Oct 17 16:59:17 2011 -0400
@@ -375,6 +375,9 @@
module.add_container('std::vector< double >', 'double', container_type='vector')
module.add_container('ns3::Bands', 'ns3::BandInfo', container_type='vector')
module.add_container('std::vector< ns3::Ptr< ns3::SpectrumPhy > >', 'ns3::Ptr< ns3::SpectrumPhy >', container_type='vector')
+ typehandlers.add_type_alias('ns3::Callback< void, ns3::Ptr< ns3::Packet const >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >', 'ns3::GenericPhyTxEndCallback')
+ typehandlers.add_type_alias('ns3::Callback< void, ns3::Ptr< ns3::Packet const >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >*', 'ns3::GenericPhyTxEndCallback*')
+ typehandlers.add_type_alias('ns3::Callback< void, ns3::Ptr< ns3::Packet const >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >&', 'ns3::GenericPhyTxEndCallback&')
typehandlers.add_type_alias('ns3::Callback< void, ns3::Ptr< ns3::Packet >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >', 'ns3::GenericPhyRxEndOkCallback')
typehandlers.add_type_alias('ns3::Callback< void, ns3::Ptr< ns3::Packet >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >*', 'ns3::GenericPhyRxEndOkCallback*')
typehandlers.add_type_alias('ns3::Callback< void, ns3::Ptr< ns3::Packet >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >&', 'ns3::GenericPhyRxEndOkCallback&')
@@ -411,18 +414,15 @@
typehandlers.add_type_alias('ns3::Vector3DChecker*', 'ns3::VectorChecker*')
typehandlers.add_type_alias('ns3::Vector3DChecker&', 'ns3::VectorChecker&')
module.add_typedef(root_module['ns3::Vector3DChecker'], 'VectorChecker')
- typehandlers.add_type_alias('ns3::Callback< bool, ns3::Ptr< ns3::Packet >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >', 'ns3::GenericPhyTxStartCallback')
- typehandlers.add_type_alias('ns3::Callback< bool, ns3::Ptr< ns3::Packet >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >*', 'ns3::GenericPhyTxStartCallback*')
- typehandlers.add_type_alias('ns3::Callback< bool, ns3::Ptr< ns3::Packet >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >&', 'ns3::GenericPhyTxStartCallback&')
typehandlers.add_type_alias('ns3::Callback< void, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >', 'ns3::GenericPhyRxEndErrorCallback')
typehandlers.add_type_alias('ns3::Callback< void, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >*', 'ns3::GenericPhyRxEndErrorCallback*')
typehandlers.add_type_alias('ns3::Callback< void, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >&', 'ns3::GenericPhyRxEndErrorCallback&')
typehandlers.add_type_alias('std::vector< double, std::allocator< double > >', 'ns3::Values')
typehandlers.add_type_alias('std::vector< double, std::allocator< double > >*', 'ns3::Values*')
typehandlers.add_type_alias('std::vector< double, std::allocator< double > >&', 'ns3::Values&')
- typehandlers.add_type_alias('ns3::Callback< void, ns3::Ptr< ns3::Packet const >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >', 'ns3::GenericPhyTxEndCallback')
- typehandlers.add_type_alias('ns3::Callback< void, ns3::Ptr< ns3::Packet const >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >*', 'ns3::GenericPhyTxEndCallback*')
- typehandlers.add_type_alias('ns3::Callback< void, ns3::Ptr< ns3::Packet const >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >&', 'ns3::GenericPhyTxEndCallback&')
+ typehandlers.add_type_alias('ns3::Callback< bool, ns3::Ptr< ns3::Packet >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >', 'ns3::GenericPhyTxStartCallback')
+ typehandlers.add_type_alias('ns3::Callback< bool, ns3::Ptr< ns3::Packet >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >*', 'ns3::GenericPhyTxStartCallback*')
+ typehandlers.add_type_alias('ns3::Callback< bool, ns3::Ptr< ns3::Packet >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >&', 'ns3::GenericPhyTxStartCallback&')
typehandlers.add_type_alias('std::map< unsigned int, ns3::SpectrumConverter, std::less< unsigned int >, std::allocator< std::pair< unsigned int const, ns3::SpectrumConverter > > >', 'ns3::SpectrumConverterMap_t')
typehandlers.add_type_alias('std::map< unsigned int, ns3::SpectrumConverter, std::less< unsigned int >, std::allocator< std::pair< unsigned int const, ns3::SpectrumConverter > > >*', 'ns3::SpectrumConverterMap_t*')
typehandlers.add_type_alias('std::map< unsigned int, ns3::SpectrumConverter, std::less< unsigned int >, std::allocator< std::pair< unsigned int const, ns3::SpectrumConverter > > >&', 'ns3::SpectrumConverterMap_t&')
@@ -3622,14 +3622,14 @@
cls.add_constructor([])
## spectrum-phy.h (module 'spectrum'): ns3::SpectrumPhy::SpectrumPhy(ns3::SpectrumPhy const & arg0) [copy constructor]
cls.add_constructor([param('ns3::SpectrumPhy const &', 'arg0')])
- ## spectrum-phy.h (module 'spectrum'): ns3::Ptr<ns3::Object> ns3::SpectrumPhy::GetDevice() [member function]
+ ## spectrum-phy.h (module 'spectrum'): ns3::Ptr<ns3::NetDevice> ns3::SpectrumPhy::GetDevice() [member function]
cls.add_method('GetDevice',
- 'ns3::Ptr< ns3::Object >',
+ 'ns3::Ptr< ns3::NetDevice >',
[],
is_pure_virtual=True, is_virtual=True)
- ## spectrum-phy.h (module 'spectrum'): ns3::Ptr<ns3::Object> ns3::SpectrumPhy::GetMobility() [member function]
+ ## spectrum-phy.h (module 'spectrum'): ns3::Ptr<ns3::MobilityModel> ns3::SpectrumPhy::GetMobility() [member function]
cls.add_method('GetMobility',
- 'ns3::Ptr< ns3::Object >',
+ 'ns3::Ptr< ns3::MobilityModel >',
[],
is_pure_virtual=True, is_virtual=True)
## spectrum-phy.h (module 'spectrum'): ns3::Ptr<ns3::SpectrumModel const> ns3::SpectrumPhy::GetRxSpectrumModel() const [member function]
@@ -3647,15 +3647,15 @@
'void',
[param('ns3::Ptr< ns3::SpectrumChannel >', 'c')],
is_pure_virtual=True, is_virtual=True)
- ## spectrum-phy.h (module 'spectrum'): void ns3::SpectrumPhy::SetDevice(ns3::Ptr<ns3::Object> d) [member function]
+ ## spectrum-phy.h (module 'spectrum'): void ns3::SpectrumPhy::SetDevice(ns3::Ptr<ns3::NetDevice> d) [member function]
cls.add_method('SetDevice',
'void',
- [param('ns3::Ptr< ns3::Object >', 'd')],
+ [param('ns3::Ptr< ns3::NetDevice >', 'd')],
is_pure_virtual=True, is_virtual=True)
- ## spectrum-phy.h (module 'spectrum'): void ns3::SpectrumPhy::SetMobility(ns3::Ptr<ns3::Object> m) [member function]
+ ## spectrum-phy.h (module 'spectrum'): void ns3::SpectrumPhy::SetMobility(ns3::Ptr<ns3::MobilityModel> m) [member function]
cls.add_method('SetMobility',
'void',
- [param('ns3::Ptr< ns3::Object >', 'm')],
+ [param('ns3::Ptr< ns3::MobilityModel >', 'm')],
is_pure_virtual=True, is_virtual=True)
## spectrum-phy.h (module 'spectrum'): void ns3::SpectrumPhy::StartRx(ns3::Ptr<ns3::PacketBurst> p, ns3::Ptr<ns3::SpectrumValue const> rxPsd, ns3::SpectrumType st, ns3::Time duration) [member function]
cls.add_method('StartRx',
@@ -4051,9 +4051,9 @@
cls.add_constructor([param('ns3::WaveformGenerator const &', 'arg0')])
## waveform-generator.h (module 'spectrum'): ns3::WaveformGenerator::WaveformGenerator() [constructor]
cls.add_constructor([])
- ## waveform-generator.h (module 'spectrum'): ns3::Ptr<ns3::Object> ns3::WaveformGenerator::GetDevice() [member function]
+ ## waveform-generator.h (module 'spectrum'): ns3::Ptr<ns3::NetDevice> ns3::WaveformGenerator::GetDevice() [member function]
cls.add_method('GetDevice',
- 'ns3::Ptr< ns3::Object >',
+ 'ns3::Ptr< ns3::NetDevice >',
[],
is_virtual=True)
## waveform-generator.h (module 'spectrum'): double ns3::WaveformGenerator::GetDutyCycle() const [member function]
@@ -4061,9 +4061,9 @@
'double',
[],
is_const=True)
- ## waveform-generator.h (module 'spectrum'): ns3::Ptr<ns3::Object> ns3::WaveformGenerator::GetMobility() [member function]
+ ## waveform-generator.h (module 'spectrum'): ns3::Ptr<ns3::MobilityModel> ns3::WaveformGenerator::GetMobility() [member function]
cls.add_method('GetMobility',
- 'ns3::Ptr< ns3::Object >',
+ 'ns3::Ptr< ns3::MobilityModel >',
[],
is_virtual=True)
## waveform-generator.h (module 'spectrum'): ns3::Time ns3::WaveformGenerator::GetPeriod() const [member function]
@@ -4090,19 +4090,19 @@
'void',
[param('ns3::Ptr< ns3::SpectrumChannel >', 'c')],
is_virtual=True)
- ## waveform-generator.h (module 'spectrum'): void ns3::WaveformGenerator::SetDevice(ns3::Ptr<ns3::Object> d) [member function]
+ ## waveform-generator.h (module 'spectrum'): void ns3::WaveformGenerator::SetDevice(ns3::Ptr<ns3::NetDevice> d) [member function]
cls.add_method('SetDevice',
'void',
- [param('ns3::Ptr< ns3::Object >', 'd')],
+ [param('ns3::Ptr< ns3::NetDevice >', 'd')],
is_virtual=True)
## waveform-generator.h (module 'spectrum'): void ns3::WaveformGenerator::SetDutyCycle(double value) [member function]
cls.add_method('SetDutyCycle',
'void',
[param('double', 'value')])
- ## waveform-generator.h (module 'spectrum'): void ns3::WaveformGenerator::SetMobility(ns3::Ptr<ns3::Object> m) [member function]
+ ## waveform-generator.h (module 'spectrum'): void ns3::WaveformGenerator::SetMobility(ns3::Ptr<ns3::MobilityModel> m) [member function]
cls.add_method('SetMobility',
'void',
- [param('ns3::Ptr< ns3::Object >', 'm')],
+ [param('ns3::Ptr< ns3::MobilityModel >', 'm')],
is_virtual=True)
## waveform-generator.h (module 'spectrum'): void ns3::WaveformGenerator::SetPeriod(ns3::Time period) [member function]
cls.add_method('SetPeriod',
@@ -4563,14 +4563,14 @@
cls.add_constructor([param('ns3::HalfDuplexIdealPhy const &', 'arg0')])
## half-duplex-ideal-phy.h (module 'spectrum'): ns3::HalfDuplexIdealPhy::HalfDuplexIdealPhy() [constructor]
cls.add_constructor([])
- ## half-duplex-ideal-phy.h (module 'spectrum'): ns3::Ptr<ns3::Object> ns3::HalfDuplexIdealPhy::GetDevice() [member function]
+ ## half-duplex-ideal-phy.h (module 'spectrum'): ns3::Ptr<ns3::NetDevice> ns3::HalfDuplexIdealPhy::GetDevice() [member function]
cls.add_method('GetDevice',
- 'ns3::Ptr< ns3::Object >',
+ 'ns3::Ptr< ns3::NetDevice >',
[],
is_virtual=True)
- ## half-duplex-ideal-phy.h (module 'spectrum'): ns3::Ptr<ns3::Object> ns3::HalfDuplexIdealPhy::GetMobility() [member function]
+ ## half-duplex-ideal-phy.h (module 'spectrum'): ns3::Ptr<ns3::MobilityModel> ns3::HalfDuplexIdealPhy::GetMobility() [member function]
cls.add_method('GetMobility',
- 'ns3::Ptr< ns3::Object >',
+ 'ns3::Ptr< ns3::MobilityModel >',
[],
is_virtual=True)
## half-duplex-ideal-phy.h (module 'spectrum'): ns3::DataRate ns3::HalfDuplexIdealPhy::GetRate() const [member function]
@@ -4597,10 +4597,10 @@
'void',
[param('ns3::Ptr< ns3::SpectrumChannel >', 'c')],
is_virtual=True)
- ## half-duplex-ideal-phy.h (module 'spectrum'): void ns3::HalfDuplexIdealPhy::SetDevice(ns3::Ptr<ns3::Object> d) [member function]
+ ## half-duplex-ideal-phy.h (module 'spectrum'): void ns3::HalfDuplexIdealPhy::SetDevice(ns3::Ptr<ns3::NetDevice> d) [member function]
cls.add_method('SetDevice',
'void',
- [param('ns3::Ptr< ns3::Object >', 'd')],
+ [param('ns3::Ptr< ns3::NetDevice >', 'd')],
is_virtual=True)
## half-duplex-ideal-phy.h (module 'spectrum'): void ns3::HalfDuplexIdealPhy::SetGenericPhyRxEndErrorCallback(ns3::GenericPhyRxEndErrorCallback c) [member function]
cls.add_method('SetGenericPhyRxEndErrorCallback',
@@ -4618,10 +4618,10 @@
cls.add_method('SetGenericPhyTxEndCallback',
'void',
[param('ns3::GenericPhyTxEndCallback', 'c')])
- ## half-duplex-ideal-phy.h (module 'spectrum'): void ns3::HalfDuplexIdealPhy::SetMobility(ns3::Ptr<ns3::Object> m) [member function]
+ ## half-duplex-ideal-phy.h (module 'spectrum'): void ns3::HalfDuplexIdealPhy::SetMobility(ns3::Ptr<ns3::MobilityModel> m) [member function]
cls.add_method('SetMobility',
'void',
- [param('ns3::Ptr< ns3::Object >', 'm')],
+ [param('ns3::Ptr< ns3::MobilityModel >', 'm')],
is_virtual=True)
## half-duplex-ideal-phy.h (module 'spectrum'): void ns3::HalfDuplexIdealPhy::SetNoisePowerSpectralDensity(ns3::Ptr<ns3::SpectrumValue const> noisePsd) [member function]
cls.add_method('SetNoisePowerSpectralDensity',
@@ -5670,14 +5670,14 @@
cls.add_constructor([param('ns3::SpectrumAnalyzer const &', 'arg0')])
## spectrum-analyzer.h (module 'spectrum'): ns3::SpectrumAnalyzer::SpectrumAnalyzer() [constructor]
cls.add_constructor([])
- ## spectrum-analyzer.h (module 'spectrum'): ns3::Ptr<ns3::Object> ns3::SpectrumAnalyzer::GetDevice() [member function]
+ ## spectrum-analyzer.h (module 'spectrum'): ns3::Ptr<ns3::NetDevice> ns3::SpectrumAnalyzer::GetDevice() [member function]
cls.add_method('GetDevice',
- 'ns3::Ptr< ns3::Object >',
+ 'ns3::Ptr< ns3::NetDevice >',
[],
is_virtual=True)
- ## spectrum-analyzer.h (module 'spectrum'): ns3::Ptr<ns3::Object> ns3::SpectrumAnalyzer::GetMobility() [member function]
+ ## spectrum-analyzer.h (module 'spectrum'): ns3::Ptr<ns3::MobilityModel> ns3::SpectrumAnalyzer::GetMobility() [member function]
cls.add_method('GetMobility',
- 'ns3::Ptr< ns3::Object >',
+ 'ns3::Ptr< ns3::MobilityModel >',
[],
is_virtual=True)
## spectrum-analyzer.h (module 'spectrum'): ns3::Ptr<ns3::SpectrumModel const> ns3::SpectrumAnalyzer::GetRxSpectrumModel() const [member function]
@@ -5695,15 +5695,15 @@
'void',
[param('ns3::Ptr< ns3::SpectrumChannel >', 'c')],
is_virtual=True)
- ## spectrum-analyzer.h (module 'spectrum'): void ns3::SpectrumAnalyzer::SetDevice(ns3::Ptr<ns3::Object> d) [member function]
+ ## spectrum-analyzer.h (module 'spectrum'): void ns3::SpectrumAnalyzer::SetDevice(ns3::Ptr<ns3::NetDevice> d) [member function]
cls.add_method('SetDevice',
'void',
- [param('ns3::Ptr< ns3::Object >', 'd')],
+ [param('ns3::Ptr< ns3::NetDevice >', 'd')],
is_virtual=True)
- ## spectrum-analyzer.h (module 'spectrum'): void ns3::SpectrumAnalyzer::SetMobility(ns3::Ptr<ns3::Object> m) [member function]
+ ## spectrum-analyzer.h (module 'spectrum'): void ns3::SpectrumAnalyzer::SetMobility(ns3::Ptr<ns3::MobilityModel> m) [member function]
cls.add_method('SetMobility',
'void',
- [param('ns3::Ptr< ns3::Object >', 'm')],
+ [param('ns3::Ptr< ns3::MobilityModel >', 'm')],
is_virtual=True)
## spectrum-analyzer.h (module 'spectrum'): void ns3::SpectrumAnalyzer::SetRxSpectrumModel(ns3::Ptr<ns3::SpectrumModel> m) [member function]
cls.add_method('SetRxSpectrumModel',
--- a/src/spectrum/bindings/modulegen__gcc_LP64.py Sat Aug 20 14:41:19 2011 -0400
+++ b/src/spectrum/bindings/modulegen__gcc_LP64.py Mon Oct 17 16:59:17 2011 -0400
@@ -375,6 +375,9 @@
module.add_container('std::vector< double >', 'double', container_type='vector')
module.add_container('ns3::Bands', 'ns3::BandInfo', container_type='vector')
module.add_container('std::vector< ns3::Ptr< ns3::SpectrumPhy > >', 'ns3::Ptr< ns3::SpectrumPhy >', container_type='vector')
+ typehandlers.add_type_alias('ns3::Callback< void, ns3::Ptr< ns3::Packet const >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >', 'ns3::GenericPhyTxEndCallback')
+ typehandlers.add_type_alias('ns3::Callback< void, ns3::Ptr< ns3::Packet const >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >*', 'ns3::GenericPhyTxEndCallback*')
+ typehandlers.add_type_alias('ns3::Callback< void, ns3::Ptr< ns3::Packet const >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >&', 'ns3::GenericPhyTxEndCallback&')
typehandlers.add_type_alias('ns3::Callback< void, ns3::Ptr< ns3::Packet >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >', 'ns3::GenericPhyRxEndOkCallback')
typehandlers.add_type_alias('ns3::Callback< void, ns3::Ptr< ns3::Packet >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >*', 'ns3::GenericPhyRxEndOkCallback*')
typehandlers.add_type_alias('ns3::Callback< void, ns3::Ptr< ns3::Packet >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >&', 'ns3::GenericPhyRxEndOkCallback&')
@@ -411,18 +414,15 @@
typehandlers.add_type_alias('ns3::Vector3DChecker*', 'ns3::VectorChecker*')
typehandlers.add_type_alias('ns3::Vector3DChecker&', 'ns3::VectorChecker&')
module.add_typedef(root_module['ns3::Vector3DChecker'], 'VectorChecker')
- typehandlers.add_type_alias('ns3::Callback< bool, ns3::Ptr< ns3::Packet >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >', 'ns3::GenericPhyTxStartCallback')
- typehandlers.add_type_alias('ns3::Callback< bool, ns3::Ptr< ns3::Packet >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >*', 'ns3::GenericPhyTxStartCallback*')
- typehandlers.add_type_alias('ns3::Callback< bool, ns3::Ptr< ns3::Packet >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >&', 'ns3::GenericPhyTxStartCallback&')
typehandlers.add_type_alias('ns3::Callback< void, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >', 'ns3::GenericPhyRxEndErrorCallback')
typehandlers.add_type_alias('ns3::Callback< void, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >*', 'ns3::GenericPhyRxEndErrorCallback*')
typehandlers.add_type_alias('ns3::Callback< void, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >&', 'ns3::GenericPhyRxEndErrorCallback&')
typehandlers.add_type_alias('std::vector< double, std::allocator< double > >', 'ns3::Values')
typehandlers.add_type_alias('std::vector< double, std::allocator< double > >*', 'ns3::Values*')
typehandlers.add_type_alias('std::vector< double, std::allocator< double > >&', 'ns3::Values&')
- typehandlers.add_type_alias('ns3::Callback< void, ns3::Ptr< ns3::Packet const >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >', 'ns3::GenericPhyTxEndCallback')
- typehandlers.add_type_alias('ns3::Callback< void, ns3::Ptr< ns3::Packet const >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >*', 'ns3::GenericPhyTxEndCallback*')
- typehandlers.add_type_alias('ns3::Callback< void, ns3::Ptr< ns3::Packet const >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >&', 'ns3::GenericPhyTxEndCallback&')
+ typehandlers.add_type_alias('ns3::Callback< bool, ns3::Ptr< ns3::Packet >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >', 'ns3::GenericPhyTxStartCallback')
+ typehandlers.add_type_alias('ns3::Callback< bool, ns3::Ptr< ns3::Packet >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >*', 'ns3::GenericPhyTxStartCallback*')
+ typehandlers.add_type_alias('ns3::Callback< bool, ns3::Ptr< ns3::Packet >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >&', 'ns3::GenericPhyTxStartCallback&')
typehandlers.add_type_alias('std::map< unsigned int, ns3::SpectrumConverter, std::less< unsigned int >, std::allocator< std::pair< unsigned int const, ns3::SpectrumConverter > > >', 'ns3::SpectrumConverterMap_t')
typehandlers.add_type_alias('std::map< unsigned int, ns3::SpectrumConverter, std::less< unsigned int >, std::allocator< std::pair< unsigned int const, ns3::SpectrumConverter > > >*', 'ns3::SpectrumConverterMap_t*')
typehandlers.add_type_alias('std::map< unsigned int, ns3::SpectrumConverter, std::less< unsigned int >, std::allocator< std::pair< unsigned int const, ns3::SpectrumConverter > > >&', 'ns3::SpectrumConverterMap_t&')
@@ -3622,14 +3622,14 @@
cls.add_constructor([])
## spectrum-phy.h (module 'spectrum'): ns3::SpectrumPhy::SpectrumPhy(ns3::SpectrumPhy const & arg0) [copy constructor]
cls.add_constructor([param('ns3::SpectrumPhy const &', 'arg0')])
- ## spectrum-phy.h (module 'spectrum'): ns3::Ptr<ns3::Object> ns3::SpectrumPhy::GetDevice() [member function]
+ ## spectrum-phy.h (module 'spectrum'): ns3::Ptr<ns3::NetDevice> ns3::SpectrumPhy::GetDevice() [member function]
cls.add_method('GetDevice',
- 'ns3::Ptr< ns3::Object >',
+ 'ns3::Ptr< ns3::NetDevice >',
[],
is_pure_virtual=True, is_virtual=True)
- ## spectrum-phy.h (module 'spectrum'): ns3::Ptr<ns3::Object> ns3::SpectrumPhy::GetMobility() [member function]
+ ## spectrum-phy.h (module 'spectrum'): ns3::Ptr<ns3::MobilityModel> ns3::SpectrumPhy::GetMobility() [member function]
cls.add_method('GetMobility',
- 'ns3::Ptr< ns3::Object >',
+ 'ns3::Ptr< ns3::MobilityModel >',
[],
is_pure_virtual=True, is_virtual=True)
## spectrum-phy.h (module 'spectrum'): ns3::Ptr<ns3::SpectrumModel const> ns3::SpectrumPhy::GetRxSpectrumModel() const [member function]
@@ -3647,15 +3647,15 @@
'void',
[param('ns3::Ptr< ns3::SpectrumChannel >', 'c')],
is_pure_virtual=True, is_virtual=True)
- ## spectrum-phy.h (module 'spectrum'): void ns3::SpectrumPhy::SetDevice(ns3::Ptr<ns3::Object> d) [member function]
+ ## spectrum-phy.h (module 'spectrum'): void ns3::SpectrumPhy::SetDevice(ns3::Ptr<ns3::NetDevice> d) [member function]
cls.add_method('SetDevice',
'void',
- [param('ns3::Ptr< ns3::Object >', 'd')],
+ [param('ns3::Ptr< ns3::NetDevice >', 'd')],
is_pure_virtual=True, is_virtual=True)
- ## spectrum-phy.h (module 'spectrum'): void ns3::SpectrumPhy::SetMobility(ns3::Ptr<ns3::Object> m) [member function]
+ ## spectrum-phy.h (module 'spectrum'): void ns3::SpectrumPhy::SetMobility(ns3::Ptr<ns3::MobilityModel> m) [member function]
cls.add_method('SetMobility',
'void',
- [param('ns3::Ptr< ns3::Object >', 'm')],
+ [param('ns3::Ptr< ns3::MobilityModel >', 'm')],
is_pure_virtual=True, is_virtual=True)
## spectrum-phy.h (module 'spectrum'): void ns3::SpectrumPhy::StartRx(ns3::Ptr<ns3::PacketBurst> p, ns3::Ptr<ns3::SpectrumValue const> rxPsd, ns3::SpectrumType st, ns3::Time duration) [member function]
cls.add_method('StartRx',
@@ -4051,9 +4051,9 @@
cls.add_constructor([param('ns3::WaveformGenerator const &', 'arg0')])
## waveform-generator.h (module 'spectrum'): ns3::WaveformGenerator::WaveformGenerator() [constructor]
cls.add_constructor([])
- ## waveform-generator.h (module 'spectrum'): ns3::Ptr<ns3::Object> ns3::WaveformGenerator::GetDevice() [member function]
+ ## waveform-generator.h (module 'spectrum'): ns3::Ptr<ns3::NetDevice> ns3::WaveformGenerator::GetDevice() [member function]
cls.add_method('GetDevice',
- 'ns3::Ptr< ns3::Object >',
+ 'ns3::Ptr< ns3::NetDevice >',
[],
is_virtual=True)
## waveform-generator.h (module 'spectrum'): double ns3::WaveformGenerator::GetDutyCycle() const [member function]
@@ -4061,9 +4061,9 @@
'double',
[],
is_const=True)
- ## waveform-generator.h (module 'spectrum'): ns3::Ptr<ns3::Object> ns3::WaveformGenerator::GetMobility() [member function]
+ ## waveform-generator.h (module 'spectrum'): ns3::Ptr<ns3::MobilityModel> ns3::WaveformGenerator::GetMobility() [member function]
cls.add_method('GetMobility',
- 'ns3::Ptr< ns3::Object >',
+ 'ns3::Ptr< ns3::MobilityModel >',
[],
is_virtual=True)
## waveform-generator.h (module 'spectrum'): ns3::Time ns3::WaveformGenerator::GetPeriod() const [member function]
@@ -4090,19 +4090,19 @@
'void',
[param('ns3::Ptr< ns3::SpectrumChannel >', 'c')],
is_virtual=True)
- ## waveform-generator.h (module 'spectrum'): void ns3::WaveformGenerator::SetDevice(ns3::Ptr<ns3::Object> d) [member function]
+ ## waveform-generator.h (module 'spectrum'): void ns3::WaveformGenerator::SetDevice(ns3::Ptr<ns3::NetDevice> d) [member function]
cls.add_method('SetDevice',
'void',
- [param('ns3::Ptr< ns3::Object >', 'd')],
+ [param('ns3::Ptr< ns3::NetDevice >', 'd')],
is_virtual=True)
## waveform-generator.h (module 'spectrum'): void ns3::WaveformGenerator::SetDutyCycle(double value) [member function]
cls.add_method('SetDutyCycle',
'void',
[param('double', 'value')])
- ## waveform-generator.h (module 'spectrum'): void ns3::WaveformGenerator::SetMobility(ns3::Ptr<ns3::Object> m) [member function]
+ ## waveform-generator.h (module 'spectrum'): void ns3::WaveformGenerator::SetMobility(ns3::Ptr<ns3::MobilityModel> m) [member function]
cls.add_method('SetMobility',
'void',
- [param('ns3::Ptr< ns3::Object >', 'm')],
+ [param('ns3::Ptr< ns3::MobilityModel >', 'm')],
is_virtual=True)
## waveform-generator.h (module 'spectrum'): void ns3::WaveformGenerator::SetPeriod(ns3::Time period) [member function]
cls.add_method('SetPeriod',
@@ -4563,14 +4563,14 @@
cls.add_constructor([param('ns3::HalfDuplexIdealPhy const &', 'arg0')])
## half-duplex-ideal-phy.h (module 'spectrum'): ns3::HalfDuplexIdealPhy::HalfDuplexIdealPhy() [constructor]
cls.add_constructor([])
- ## half-duplex-ideal-phy.h (module 'spectrum'): ns3::Ptr<ns3::Object> ns3::HalfDuplexIdealPhy::GetDevice() [member function]
+ ## half-duplex-ideal-phy.h (module 'spectrum'): ns3::Ptr<ns3::NetDevice> ns3::HalfDuplexIdealPhy::GetDevice() [member function]
cls.add_method('GetDevice',
- 'ns3::Ptr< ns3::Object >',
+ 'ns3::Ptr< ns3::NetDevice >',
[],
is_virtual=True)
- ## half-duplex-ideal-phy.h (module 'spectrum'): ns3::Ptr<ns3::Object> ns3::HalfDuplexIdealPhy::GetMobility() [member function]
+ ## half-duplex-ideal-phy.h (module 'spectrum'): ns3::Ptr<ns3::MobilityModel> ns3::HalfDuplexIdealPhy::GetMobility() [member function]
cls.add_method('GetMobility',
- 'ns3::Ptr< ns3::Object >',
+ 'ns3::Ptr< ns3::MobilityModel >',
[],
is_virtual=True)
## half-duplex-ideal-phy.h (module 'spectrum'): ns3::DataRate ns3::HalfDuplexIdealPhy::GetRate() const [member function]
@@ -4597,10 +4597,10 @@
'void',
[param('ns3::Ptr< ns3::SpectrumChannel >', 'c')],
is_virtual=True)
- ## half-duplex-ideal-phy.h (module 'spectrum'): void ns3::HalfDuplexIdealPhy::SetDevice(ns3::Ptr<ns3::Object> d) [member function]
+ ## half-duplex-ideal-phy.h (module 'spectrum'): void ns3::HalfDuplexIdealPhy::SetDevice(ns3::Ptr<ns3::NetDevice> d) [member function]
cls.add_method('SetDevice',
'void',
- [param('ns3::Ptr< ns3::Object >', 'd')],
+ [param('ns3::Ptr< ns3::NetDevice >', 'd')],
is_virtual=True)
## half-duplex-ideal-phy.h (module 'spectrum'): void ns3::HalfDuplexIdealPhy::SetGenericPhyRxEndErrorCallback(ns3::GenericPhyRxEndErrorCallback c) [member function]
cls.add_method('SetGenericPhyRxEndErrorCallback',
@@ -4618,10 +4618,10 @@
cls.add_method('SetGenericPhyTxEndCallback',
'void',
[param('ns3::GenericPhyTxEndCallback', 'c')])
- ## half-duplex-ideal-phy.h (module 'spectrum'): void ns3::HalfDuplexIdealPhy::SetMobility(ns3::Ptr<ns3::Object> m) [member function]
+ ## half-duplex-ideal-phy.h (module 'spectrum'): void ns3::HalfDuplexIdealPhy::SetMobility(ns3::Ptr<ns3::MobilityModel> m) [member function]
cls.add_method('SetMobility',
'void',
- [param('ns3::Ptr< ns3::Object >', 'm')],
+ [param('ns3::Ptr< ns3::MobilityModel >', 'm')],
is_virtual=True)
## half-duplex-ideal-phy.h (module 'spectrum'): void ns3::HalfDuplexIdealPhy::SetNoisePowerSpectralDensity(ns3::Ptr<ns3::SpectrumValue const> noisePsd) [member function]
cls.add_method('SetNoisePowerSpectralDensity',
@@ -5670,14 +5670,14 @@
cls.add_constructor([param('ns3::SpectrumAnalyzer const &', 'arg0')])
## spectrum-analyzer.h (module 'spectrum'): ns3::SpectrumAnalyzer::SpectrumAnalyzer() [constructor]
cls.add_constructor([])
- ## spectrum-analyzer.h (module 'spectrum'): ns3::Ptr<ns3::Object> ns3::SpectrumAnalyzer::GetDevice() [member function]
+ ## spectrum-analyzer.h (module 'spectrum'): ns3::Ptr<ns3::NetDevice> ns3::SpectrumAnalyzer::GetDevice() [member function]
cls.add_method('GetDevice',
- 'ns3::Ptr< ns3::Object >',
+ 'ns3::Ptr< ns3::NetDevice >',
[],
is_virtual=True)
- ## spectrum-analyzer.h (module 'spectrum'): ns3::Ptr<ns3::Object> ns3::SpectrumAnalyzer::GetMobility() [member function]
+ ## spectrum-analyzer.h (module 'spectrum'): ns3::Ptr<ns3::MobilityModel> ns3::SpectrumAnalyzer::GetMobility() [member function]
cls.add_method('GetMobility',
- 'ns3::Ptr< ns3::Object >',
+ 'ns3::Ptr< ns3::MobilityModel >',
[],
is_virtual=True)
## spectrum-analyzer.h (module 'spectrum'): ns3::Ptr<ns3::SpectrumModel const> ns3::SpectrumAnalyzer::GetRxSpectrumModel() const [member function]
@@ -5695,15 +5695,15 @@
'void',
[param('ns3::Ptr< ns3::SpectrumChannel >', 'c')],
is_virtual=True)
- ## spectrum-analyzer.h (module 'spectrum'): void ns3::SpectrumAnalyzer::SetDevice(ns3::Ptr<ns3::Object> d) [member function]
+ ## spectrum-analyzer.h (module 'spectrum'): void ns3::SpectrumAnalyzer::SetDevice(ns3::Ptr<ns3::NetDevice> d) [member function]
cls.add_method('SetDevice',
'void',
- [param('ns3::Ptr< ns3::Object >', 'd')],
+ [param('ns3::Ptr< ns3::NetDevice >', 'd')],
is_virtual=True)
- ## spectrum-analyzer.h (module 'spectrum'): void ns3::SpectrumAnalyzer::SetMobility(ns3::Ptr<ns3::Object> m) [member function]
+ ## spectrum-analyzer.h (module 'spectrum'): void ns3::SpectrumAnalyzer::SetMobility(ns3::Ptr<ns3::MobilityModel> m) [member function]
cls.add_method('SetMobility',
'void',
- [param('ns3::Ptr< ns3::Object >', 'm')],
+ [param('ns3::Ptr< ns3::MobilityModel >', 'm')],
is_virtual=True)
## spectrum-analyzer.h (module 'spectrum'): void ns3::SpectrumAnalyzer::SetRxSpectrumModel(ns3::Ptr<ns3::SpectrumModel> m) [member function]
cls.add_method('SetRxSpectrumModel',
--- a/src/spectrum/examples/adhoc-aloha-ideal-phy-matrix-propagation-loss-model.cc Sat Aug 20 14:41:19 2011 -0400
+++ b/src/spectrum/examples/adhoc-aloha-ideal-phy-matrix-propagation-loss-model.cc Mon Oct 17 16:59:17 2011 -0400
@@ -40,6 +40,10 @@
#include <ns3/applications-module.h>
#include <ns3/adhoc-aloha-noack-ideal-phy-helper.h>
+#ifdef __FreeBSD__
+#define log2(x) (log (x)/M_LN2)
+#endif
+
NS_LOG_COMPONENT_DEFINE ("TestAdhocOfdmAloha");
using namespace ns3;
@@ -58,6 +62,66 @@
}
+
+/**
+ * Store the last pathloss value for each TX-RX pair. This is an
+ * example of how the PathlossTrace (provided by some SpectrumChannel
+ * implementations) work.
+ *
+ */
+class GlobalPathlossDatabase
+{
+public:
+
+ /**
+ * update the pathloss value
+ *
+ * \param context
+ * \param txPhy the transmitting PHY
+ * \param rxPhy the receiving PHY
+ * \param lossDb the loss in dB
+ */
+ void UpdatePathloss (std::string context, Ptr<SpectrumPhy> txPhy, Ptr<SpectrumPhy> rxPhy, double lossDb);
+
+ /**
+ * print the stored pathloss values to standard output
+ *
+ */
+ void Print ();
+
+private:
+ std::map<uint32_t, std::map<uint32_t, double> > m_pathlossMap;
+};
+
+void
+GlobalPathlossDatabase::UpdatePathloss (std::string context,
+ Ptr<SpectrumPhy> txPhy,
+ Ptr<SpectrumPhy> rxPhy,
+ double lossDb)
+{
+ uint32_t txNodeId = txPhy->GetMobility ()->GetObject<Node> ()->GetId ();
+ uint32_t rxNodeId = rxPhy->GetMobility ()->GetObject<Node> ()->GetId ();
+ m_pathlossMap[txNodeId][rxNodeId] = lossDb;
+}
+
+void
+GlobalPathlossDatabase::Print ()
+{
+ for (std::map<uint32_t, std::map<uint32_t, double> >::const_iterator txit = m_pathlossMap.begin ();
+ txit != m_pathlossMap.end ();
+ ++txit)
+ {
+ for (std::map<uint32_t, double>::const_iterator rxit = txit->second.begin ();
+ rxit != txit->second.end ();
+ ++rxit)
+ {
+ std::cout << txit->first << " --> " << rxit->first << " : " << rxit->second << " dB" << std::endl;
+ }
+ }
+}
+
+
+
int main (int argc, char** argv)
{
CommandLine cmd;
@@ -66,12 +130,14 @@
uint64_t phyRate = 500000;
uint32_t pktSize = 1000;
double simDuration = 0.5;
+ std::string channelType ("ns3::SingleModelSpectrumChannel");
cmd.AddValue ("verbose", "Print trace information if true", g_verbose);
cmd.AddValue ("lossDb", "link loss in dB", lossDb);
cmd.AddValue ("txPowerW", "txPower in Watts", txPowerW);
cmd.AddValue ("phyRate", "PHY rate in bps", phyRate);
cmd.AddValue ("pktSize", "packet size in bytes", pktSize);
cmd.AddValue ("simDuration", "duration of the simulation in seconds", simDuration);
+ cmd.AddValue ("channelType", "which SpectrumChannel implementation to be used", channelType);
cmd.Parse (argc, argv);
NodeContainer c;
@@ -89,7 +155,7 @@
SpectrumChannelHelper channelHelper;
- channelHelper.SetChannel ("ns3::MultiModelSpectrumChannel");
+ channelHelper.SetChannel (channelType);
channelHelper.SetPropagationDelay ("ns3::ConstantSpeedPropagationDelayModel");
Ptr<MatrixPropagationLossModel> propLoss = CreateObject<MatrixPropagationLossModel> ();
propLoss->SetLoss (c.Get (0)->GetObject<MobilityModel> (), c.Get (1)->GetObject<MobilityModel> (), lossDb, true);
@@ -136,12 +202,18 @@
Config::Connect ("/NodeList/*/DeviceList/*/Phy/RxEndOk", MakeCallback (&PhyRxEndOkTrace));
+ GlobalPathlossDatabase globalPathlossDatabase;
+ Config::Connect ("/ChannelList/*/PropagationLoss",
+ MakeCallback (&GlobalPathlossDatabase::UpdatePathloss, &globalPathlossDatabase));
+
g_rxBytes = 0;
Simulator::Stop (Seconds (simDuration + 0.000001));
Simulator::Run ();
if (g_verbose)
{
+ globalPathlossDatabase.Print ();
+
double throughputBps = (g_rxBytes * 8.0) / simDuration;
std::cout << "throughput: " << throughputBps << std::endl;
std::cout << "throughput: " << std::setw (20) << std::fixed << throughputBps << " bps" << std::endl;
--- a/src/spectrum/helper/adhoc-aloha-noack-ideal-phy-helper.cc Sat Aug 20 14:41:19 2011 -0400
+++ b/src/spectrum/helper/adhoc-aloha-noack-ideal-phy-helper.cc Mon Oct 17 16:59:17 2011 -0400
@@ -113,7 +113,7 @@
dev->SetPhy (phy);
NS_ASSERT (node);
- phy->SetMobility (node);
+ phy->SetMobility (node->GetObject<MobilityModel> ());
NS_ASSERT (dev);
phy->SetDevice (dev);
--- a/src/spectrum/helper/spectrum-analyzer-helper.cc Sat Aug 20 14:41:19 2011 -0400
+++ b/src/spectrum/helper/spectrum-analyzer-helper.cc Mon Oct 17 16:59:17 2011 -0400
@@ -142,7 +142,7 @@
dev->SetPhy (phy);
NS_ASSERT (node);
- phy->SetMobility (node);
+ phy->SetMobility (node->GetObject<MobilityModel> ());
NS_ASSERT (dev);
phy->SetDevice (dev);
--- a/src/spectrum/helper/spectrum-helper.cc Sat Aug 20 14:41:19 2011 -0400
+++ b/src/spectrum/helper/spectrum-helper.cc Mon Oct 17 16:59:17 2011 -0400
@@ -215,7 +215,7 @@
NS_ASSERT (m_channel);
Ptr<SpectrumPhy> phy = (m_phy.Create ())->GetObject<SpectrumPhy> ();
phy->SetChannel (m_channel);
- phy->SetMobility (node);
+ phy->SetMobility (node->GetObject<MobilityModel> ());
phy->SetDevice (device);
return phy;
}
--- a/src/spectrum/helper/waveform-generator-helper.cc Sat Aug 20 14:41:19 2011 -0400
+++ b/src/spectrum/helper/waveform-generator-helper.cc Mon Oct 17 16:59:17 2011 -0400
@@ -98,7 +98,7 @@
dev->SetPhy (phy);
NS_ASSERT (node);
- phy->SetMobility (node);
+ phy->SetMobility (node->GetObject<MobilityModel> ());
NS_ASSERT (dev);
phy->SetDevice (dev);
--- a/src/spectrum/model/half-duplex-ideal-phy.cc Sat Aug 20 14:41:19 2011 -0400
+++ b/src/spectrum/model/half-duplex-ideal-phy.cc Mon Oct 17 16:59:17 2011 -0400
@@ -126,7 +126,7 @@
-Ptr<Object>
+Ptr<NetDevice>
HalfDuplexIdealPhy::GetDevice ()
{
NS_LOG_FUNCTION (this);
@@ -134,7 +134,7 @@
}
-Ptr<Object>
+Ptr<MobilityModel>
HalfDuplexIdealPhy::GetMobility ()
{
NS_LOG_FUNCTION (this);
@@ -143,7 +143,7 @@
void
-HalfDuplexIdealPhy::SetDevice (Ptr<Object> d)
+HalfDuplexIdealPhy::SetDevice (Ptr<NetDevice> d)
{
NS_LOG_FUNCTION (this << d);
m_netDevice = d;
@@ -151,7 +151,7 @@
void
-HalfDuplexIdealPhy::SetMobility (Ptr<Object> m)
+HalfDuplexIdealPhy::SetMobility (Ptr<MobilityModel> m)
{
NS_LOG_FUNCTION (this << m);
m_mobility = m;
--- a/src/spectrum/model/half-duplex-ideal-phy.h Sat Aug 20 14:41:19 2011 -0400
+++ b/src/spectrum/model/half-duplex-ideal-phy.h Mon Oct 17 16:59:17 2011 -0400
@@ -94,10 +94,10 @@
// inherited from SpectrumPhy
void SetChannel (Ptr<SpectrumChannel> c);
- void SetMobility (Ptr<Object> m);
- void SetDevice (Ptr<Object> d);
- Ptr<Object> GetMobility ();
- Ptr<Object> GetDevice ();
+ void SetMobility (Ptr<MobilityModel> m);
+ void SetDevice (Ptr<NetDevice> d);
+ Ptr<MobilityModel> GetMobility ();
+ Ptr<NetDevice> GetDevice ();
Ptr<const SpectrumModel> GetRxSpectrumModel () const;
void StartRx (Ptr<PacketBurst> p, Ptr <const SpectrumValue> rxPsd, SpectrumType st, Time duration);
@@ -195,8 +195,8 @@
EventId m_endRxEventId;
- Ptr<Object> m_mobility;
- Ptr<Object> m_netDevice;
+ Ptr<MobilityModel> m_mobility;
+ Ptr<NetDevice> m_netDevice;
Ptr<SpectrumChannel> m_channel;
Ptr<SpectrumValue> m_txPsd;
--- a/src/spectrum/model/multi-model-spectrum-channel.cc Sat Aug 20 14:41:19 2011 -0400
+++ b/src/spectrum/model/multi-model-spectrum-channel.cc Mon Oct 17 16:59:17 2011 -0400
@@ -111,6 +111,15 @@
DoubleValue (1.0e9),
MakeDoubleAccessor (&MultiModelSpectrumChannel::m_maxLossDb),
MakeDoubleChecker<double> ())
+ .AddTraceSource ("PropagationLoss",
+ "If a PropagationLossModel is plugged on the channel, this trace is fired "
+ "whenever a new path loss value is calculated. The first and second parameters "
+ "to the trace are pointers respectively to the TX and RX SpectrumPhy instances, "
+ "whereas the third parameters is the loss value in dB. Note that the loss value "
+ "reported by this trace is the single-frequency loss value obtained by "
+ "PropagationLossModel, and is not affected by whether an additional "
+ "SpectrumPropagationLossModel is being used or not.",
+ MakeTraceSourceAccessor (&MultiModelSpectrumChannel::m_propagationLossTrace))
;
return tid;
}
@@ -222,7 +231,7 @@
NS_ASSERT (originalTxPowerSpectrum);
- Ptr<MobilityModel> txMobility = txPhy->GetMobility ()->GetObject<MobilityModel> ();
+ Ptr<MobilityModel> txMobility = txPhy->GetMobility ();
SpectrumModelUid_t txSpectrumModelUid = originalTxPowerSpectrum->GetSpectrumModelUid ();
NS_LOG_LOGIC (" txSpectrumModelUid " << txSpectrumModelUid);
@@ -268,13 +277,14 @@
Ptr <SpectrumValue> rxPowerSpectrum = convertedTxPowerSpectrum->Copy ();
Time delay = MicroSeconds (0);
- Ptr<MobilityModel> receiverMobility = (*rxPhyIterator)->GetMobility ()->GetObject<MobilityModel> ();
+ Ptr<MobilityModel> receiverMobility = (*rxPhyIterator)->GetMobility ();
if (txMobility && receiverMobility)
{
if (m_propagationLoss)
{
double gainDb = m_propagationLoss->CalcRxPower (0, txMobility, receiverMobility);
+ m_propagationLossTrace (txPhy, *rxPhyIterator, -gainDb);
if ( (-gainDb) > m_maxLossDb)
{
// beyond range
@@ -296,11 +306,11 @@
}
Ptr<PacketBurst> pktBurstCopy = p->Copy ();
- Ptr<Object> netDevObj = (*rxPhyIterator)->GetDevice ();
- if (netDevObj)
+ Ptr<NetDevice> netDev = (*rxPhyIterator)->GetDevice ();
+ if (netDev)
{
// the receiver has a NetDevice, so we expect that it is attached to a Node
- uint32_t dstNode = netDevObj->GetObject<NetDevice> ()->GetNode ()->GetId ();
+ uint32_t dstNode = netDev->GetNode ()->GetId ();
Simulator::ScheduleWithContext (dstNode, delay, &MultiModelSpectrumChannel::StartRx, this,
pktBurstCopy, rxPowerSpectrum, st, duration, *rxPhyIterator);
}
@@ -337,7 +347,7 @@
Ptr<NetDevice>
MultiModelSpectrumChannel::GetDevice (uint32_t i) const
{
- return m_phyVector.at (i)->GetDevice ()->GetObject<NetDevice> ();
+ return m_phyVector.at (i)->GetDevice ();
}
--- a/src/spectrum/model/multi-model-spectrum-channel.h Sat Aug 20 14:41:19 2011 -0400
+++ b/src/spectrum/model/multi-model-spectrum-channel.h Mon Oct 17 16:59:17 2011 -0400
@@ -188,6 +188,8 @@
double m_maxLossDb;
+
+ TracedCallback<Ptr<SpectrumPhy>, Ptr<SpectrumPhy>, double > m_propagationLossTrace;
};
--- a/src/spectrum/model/single-model-spectrum-channel.cc Sat Aug 20 14:41:19 2011 -0400
+++ b/src/spectrum/model/single-model-spectrum-channel.cc Mon Oct 17 16:59:17 2011 -0400
@@ -80,6 +80,15 @@
DoubleValue (1.0e9),
MakeDoubleAccessor (&SingleModelSpectrumChannel::m_maxLossDb),
MakeDoubleChecker<double> ())
+ .AddTraceSource ("PropagationLoss",
+ "If a PropagationLossModel is plugged on the channel, this trace is fired "
+ "whenever a new path loss value is calculated. The first and second parameters "
+ "to the trace are pointers respectively to the TX and RX SpectrumPhy instances, "
+ "whereas the third parameters is the loss value in dB. Note that the loss value "
+ "reported by this trace is the single-frequency loss value obtained by "
+ "PropagationLossModel, and is not affected by whether an additional "
+ "SpectrumPropagationLossModel is being used or not.",
+ MakeTraceSourceAccessor (&SingleModelSpectrumChannel::m_propagationLossTrace))
;
return tid;
}
@@ -116,7 +125,7 @@
- Ptr<MobilityModel> senderMobility = txPhy->GetMobility ()->GetObject<MobilityModel> ();
+ Ptr<MobilityModel> senderMobility = txPhy->GetMobility ();
for (PhyList::const_iterator rxPhyIterator = m_phyList.begin ();
rxPhyIterator != m_phyList.end ();
@@ -127,13 +136,14 @@
Ptr <SpectrumValue> rxPsd = Copy<SpectrumValue> (txPsd);
Time delay = MicroSeconds (0);
- Ptr<MobilityModel> receiverMobility = (*rxPhyIterator)->GetMobility ()->GetObject<MobilityModel> ();
+ Ptr<MobilityModel> receiverMobility = (*rxPhyIterator)->GetMobility ();
if (senderMobility && receiverMobility)
{
if (m_propagationLoss)
{
double gainDb = m_propagationLoss->CalcRxPower (0, senderMobility, receiverMobility);
+ m_propagationLossTrace (txPhy, *rxPhyIterator, -gainDb);
if ( (-gainDb) > m_maxLossDb)
{
// beyond range
@@ -155,11 +165,11 @@
}
Ptr<PacketBurst> pktBurstCopy = p->Copy ();
- Ptr<Object> netDevObj = (*rxPhyIterator)->GetDevice ();
- if (netDevObj)
+ Ptr<NetDevice> netDev = (*rxPhyIterator)->GetDevice ();
+ if (netDev)
{
// the receiver has a NetDevice, so we expect that it is attached to a Node
- uint32_t dstNode = netDevObj->GetObject<NetDevice> ()->GetNode ()->GetId ();
+ uint32_t dstNode = netDev->GetNode ()->GetId ();
Simulator::ScheduleWithContext (dstNode, delay, &SingleModelSpectrumChannel::StartRx, this,
pktBurstCopy, rxPsd, st, duration, *rxPhyIterator);
}
--- a/src/spectrum/model/single-model-spectrum-channel.h Sat Aug 20 14:41:19 2011 -0400
+++ b/src/spectrum/model/single-model-spectrum-channel.h Mon Oct 17 16:59:17 2011 -0400
@@ -24,6 +24,7 @@
#include <ns3/spectrum-channel.h>
#include <ns3/spectrum-model.h>
+#include <ns3/traced-callback.h>
namespace ns3 {
@@ -114,6 +115,8 @@
double m_maxLossDb;
+
+ TracedCallback<Ptr<SpectrumPhy>, Ptr<SpectrumPhy>, double > m_propagationLossTrace;
};
--- a/src/spectrum/model/spectrum-analyzer.cc Sat Aug 20 14:41:19 2011 -0400
+++ b/src/spectrum/model/spectrum-analyzer.cc Mon Oct 17 16:59:17 2011 -0400
@@ -90,14 +90,14 @@
-Ptr<Object>
+Ptr<NetDevice>
SpectrumAnalyzer::GetDevice ()
{
return m_netDevice;
}
-Ptr<Object>
+Ptr<MobilityModel>
SpectrumAnalyzer::GetMobility ()
{
return m_mobility;
@@ -111,7 +111,7 @@
}
void
-SpectrumAnalyzer::SetDevice (Ptr<Object> d)
+SpectrumAnalyzer::SetDevice (Ptr<NetDevice> d)
{
NS_LOG_FUNCTION (this << d);
m_netDevice = d;
@@ -119,7 +119,7 @@
void
-SpectrumAnalyzer::SetMobility (Ptr<Object> m)
+SpectrumAnalyzer::SetMobility (Ptr<MobilityModel> m)
{
NS_LOG_FUNCTION (this << m);
m_mobility = m;
--- a/src/spectrum/model/spectrum-analyzer.h Sat Aug 20 14:41:19 2011 -0400
+++ b/src/spectrum/model/spectrum-analyzer.h Mon Oct 17 16:59:17 2011 -0400
@@ -53,10 +53,10 @@
// inherited from SpectrumPhy
void SetChannel (Ptr<SpectrumChannel> c);
- void SetMobility (Ptr<Object> m);
- void SetDevice (Ptr<Object> d);
- Ptr<Object> GetMobility ();
- Ptr<Object> GetDevice ();
+ void SetMobility (Ptr<MobilityModel> m);
+ void SetDevice (Ptr<NetDevice> d);
+ Ptr<MobilityModel> GetMobility ();
+ Ptr<NetDevice> GetDevice ();
Ptr<const SpectrumModel> GetRxSpectrumModel () const;
void StartRx (Ptr<PacketBurst> pb, Ptr <const SpectrumValue> rxPowerSpectralDensity, SpectrumType st, Time duration);
@@ -86,8 +86,8 @@
void DoDispose ();
private:
- Ptr<Object> m_mobility;
- Ptr<Object> m_netDevice;
+ Ptr<MobilityModel> m_mobility;
+ Ptr<NetDevice> m_netDevice;
Ptr<SpectrumChannel> m_channel;
virtual void GenerateReport ();
--- a/src/spectrum/model/spectrum-phy.h Sat Aug 20 14:41:19 2011 -0400
+++ b/src/spectrum/model/spectrum-phy.h Mon Oct 17 16:59:17 2011 -0400
@@ -54,28 +54,28 @@
*
* @param d the NetDevice instance
*/
- virtual void SetDevice (Ptr<Object> d) = 0;
+ virtual void SetDevice (Ptr<NetDevice> d) = 0;
/**
* get the associated NetDevice instance
*
* @return a Ptr to the associated NetDevice instance
*/
- virtual Ptr<Object> GetDevice () = 0;
+ virtual Ptr<NetDevice> GetDevice () = 0;
/**
* Set the mobility model associated with this device.
*
* @param m the mobility model
*/
- virtual void SetMobility (Ptr<Object> m) = 0;
+ virtual void SetMobility (Ptr<MobilityModel> m) = 0;
/**
* get the associated MobilityModel instance
*
* @return a Ptr to the associated NetDevice instance
*/
- virtual Ptr<Object> GetMobility () = 0;
+ virtual Ptr<MobilityModel> GetMobility () = 0;
/**
--- a/src/spectrum/model/waveform-generator.cc Sat Aug 20 14:41:19 2011 -0400
+++ b/src/spectrum/model/waveform-generator.cc Mon Oct 17 16:59:17 2011 -0400
@@ -89,14 +89,14 @@
-Ptr<Object>
+Ptr<NetDevice>
WaveformGenerator::GetDevice ()
{
return m_netDevice;
}
-Ptr<Object>
+Ptr<MobilityModel>
WaveformGenerator::GetMobility ()
{
return m_mobility;
@@ -111,14 +111,14 @@
}
void
-WaveformGenerator::SetDevice (Ptr<Object> d)
+WaveformGenerator::SetDevice (Ptr<NetDevice> d)
{
m_netDevice = d;
}
void
-WaveformGenerator::SetMobility (Ptr<Object> m)
+WaveformGenerator::SetMobility (Ptr<MobilityModel> m)
{
m_mobility = m;
}
--- a/src/spectrum/model/waveform-generator.h Sat Aug 20 14:41:19 2011 -0400
+++ b/src/spectrum/model/waveform-generator.h Mon Oct 17 16:59:17 2011 -0400
@@ -56,10 +56,10 @@
// inherited from SpectrumPhy
void SetChannel (Ptr<SpectrumChannel> c);
- void SetMobility (Ptr<Object> m);
- void SetDevice (Ptr<Object> d);
- Ptr<Object> GetMobility ();
- Ptr<Object> GetDevice ();
+ void SetMobility (Ptr<MobilityModel> m);
+ void SetDevice (Ptr<NetDevice> d);
+ Ptr<MobilityModel> GetMobility ();
+ Ptr<NetDevice> GetDevice ();
Ptr<const SpectrumModel> GetRxSpectrumModel () const;
void StartRx (Ptr<PacketBurst> p, Ptr <const SpectrumValue> rxPsd, SpectrumType st, Time duration);
@@ -129,8 +129,8 @@
private:
virtual void DoDispose (void);
- Ptr<Object> m_mobility;
- Ptr<Object> m_netDevice;
+ Ptr<MobilityModel> m_mobility;
+ Ptr<NetDevice> m_netDevice;
Ptr<SpectrumChannel> m_channel;
virtual void GenerateWaveform ();
--- a/src/spectrum/test/spectrum-ideal-phy-test.cc Sat Aug 20 14:41:19 2011 -0400
+++ b/src/spectrum/test/spectrum-ideal-phy-test.cc Mon Oct 17 16:59:17 2011 -0400
@@ -49,6 +49,10 @@
#include <ns3/on-off-helper.h>
#include <ns3/config.h>
+#ifdef __FreeBSD__
+#define log2(x) (log(x)/M_LN2)
+#endif
+
NS_LOG_COMPONENT_DEFINE ("SpectrumIdealPhyTest");
namespace ns3 {
--- a/src/spectrum/wscript Sat Aug 20 14:41:19 2011 -0400
+++ b/src/spectrum/wscript Mon Oct 17 16:59:17 2011 -0400
@@ -39,7 +39,7 @@
'test/spectrum-ideal-phy-test.cc',
]
- headers = bld.new_task_gen('ns3header')
+ headers = bld.new_task_gen(features=['ns3header'])
headers.module = 'spectrum'
headers.source = [
'model/spectrum-model.h',
--- a/src/stats/wscript Sat Aug 20 14:41:19 2011 -0400
+++ b/src/stats/wscript Mon Oct 17 16:59:17 2011 -0400
@@ -1,7 +1,9 @@
## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
def configure(conf):
- conf.env['SQLITE_STATS'] = conf.check(lib='sqlite3', define_name='SQLITE3', uselib='SQLITE3')
+ conf.env['SQLITE_STATS'] = conf.check_nonfatal(lib='sqlite3', define_name='SQLITE3', uselib_store='SQLITE3')
+ if not conf.env['SQLITE_STATS']:
+ conf.env['SQLITE_STATS'] = conf.pkg_check_modules('SQLITE3', 'sqlite3', mandatory=False)
conf.report_optional_feature("SqliteDataOutput", "SQlite stats data output",
conf.env['SQLITE_STATS'],
"library 'sqlite3' not found")
@@ -23,7 +25,7 @@
'test/basic-data-calculators-test-suite.cc',
]
- headers = bld.new_task_gen('ns3header')
+ headers = bld.new_task_gen(features=['ns3header'])
headers.module = 'stats'
headers.source = [
'model/data-calculator.h',
@@ -38,6 +40,6 @@
if bld.env['SQLITE_STATS']:
headers.source.append('model/sqlite-data-output.h')
obj.source.append('model/sqlite-data-output.cc')
- obj.uselib = 'SQLITE3'
+ obj.use.append('SQLITE3')
bld.ns3_python_bindings()
--- a/src/tap-bridge/examples/wscript Sat Aug 20 14:41:19 2011 -0400
+++ b/src/tap-bridge/examples/wscript Mon Oct 17 16:59:17 2011 -0400
@@ -1,7 +1,7 @@
## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
def build(bld):
- env = bld.env_of_name('default')
+ env = bld.env
if env['ENABLE_TAP']:
obj = bld.create_ns3_program('tap-csma', ['csma', 'tap-bridge', 'internet', 'wifi'])
obj.source = 'tap-csma.cc'
--- a/src/tap-bridge/wscript Sat Aug 20 14:41:19 2011 -0400
+++ b/src/tap-bridge/wscript Mon Oct 17 16:59:17 2011 -0400
@@ -4,7 +4,7 @@
def configure(conf):
if conf.env['ENABLE_THREADING']:
- conf.env['ENABLE_TAP'] = conf.check(header_name='linux/if_tun.h',
+ conf.env['ENABLE_TAP'] = conf.check_nonfatal(header_name='linux/if_tun.h',
define_name='HAVE_IF_TUN_H')
conf.report_optional_feature("TapBridge", "Tap Bridge",
conf.env['ENABLE_TAP'],
@@ -15,7 +15,7 @@
"needs threading support which is not available")
if conf.env['ENABLE_TAP']:
- blddir = os.path.abspath(os.path.join(conf.blddir, conf.env.variant()))
+ blddir = os.path.abspath(os.path.join(conf.bldnode.abspath(), conf.variant))
tapcreatordir = os.path.abspath(os.path.join(blddir, "src/tap-bridge"))
conf.env.append_value('NS3_EXECUTABLE_PATH', tapcreatordir)
else:
@@ -34,7 +34,7 @@
'model/tap-encode-decode.cc',
'helper/tap-bridge-helper.cc',
]
- headers = bld.new_task_gen('ns3header')
+ headers = bld.new_task_gen(features=['ns3header'])
headers.module = 'tap-bridge'
headers.source = [
'model/tap-bridge.h',
--- a/src/template/wscript Sat Aug 20 14:41:19 2011 -0400
+++ b/src/template/wscript Mon Oct 17 16:59:17 2011 -0400
@@ -27,7 +27,7 @@
]
# Make headers be installed for this module.
- headers = bld.new_task_gen('ns3header')
+ headers = bld.new_task_gen(features=['ns3header'])
headers.module = 'template'
# Set the C++ header files for this module.
--- a/src/test/ns3tcp/wscript Sat Aug 20 14:41:19 2011 -0400
+++ b/src/test/ns3tcp/wscript Mon Oct 17 16:59:17 2011 -0400
@@ -16,7 +16,7 @@
return
ns3tcp = bld.create_ns3_module('ns3tcp', ['internet', 'point-to-point', 'csma', 'applications'])
- headers = bld.new_task_gen('ns3header')
+ headers = bld.new_task_gen(features=['ns3header'])
headers.module = 'ns3tcp'
headers.source = [
'ns3tcp.h',
--- a/src/test/ns3wifi/wscript Sat Aug 20 14:41:19 2011 -0400
+++ b/src/test/ns3wifi/wscript Mon Oct 17 16:59:17 2011 -0400
@@ -16,7 +16,7 @@
return
ns3wifi = bld.create_ns3_module('ns3wifi', ['internet', 'mobility', 'propagation', 'wifi', 'applications'])
- headers = bld.new_task_gen('ns3header')
+ headers = bld.new_task_gen(features=['ns3header'])
headers.module = 'ns3wifi'
headers.source = [
'ns3wifi.h',
--- a/src/test/wscript Sat Aug 20 14:41:19 2011 -0400
+++ b/src/test/wscript Mon Oct 17 16:59:17 2011 -0400
@@ -20,7 +20,7 @@
return
test = bld.create_ns3_module('test', ['internet', 'mobility', 'applications', 'csma', 'bridge', 'config-store', 'tools', 'point-to-point', 'csma-layout', 'flow-monitor'])
- headers = bld.new_task_gen('ns3header')
+ headers = bld.new_task_gen(features=['ns3header'])
headers.module = 'test'
test_test = bld.create_ns3_module_test_library('test')
--- a/src/tools/bindings/modulegen__gcc_ILP32.py Sat Aug 20 14:41:19 2011 -0400
+++ b/src/tools/bindings/modulegen__gcc_ILP32.py Mon Oct 17 16:59:17 2011 -0400
@@ -1648,10 +1648,10 @@
cls.add_method('Add',
'void',
[param('double', 'x'), param('double', 'y'), param('double', 'errorDelta')])
- ## gnuplot.h (module 'tools'): void ns3::Gnuplot2dDataset::Add(double x, double y, double minY, double maxY) [member function]
+ ## gnuplot.h (module 'tools'): void ns3::Gnuplot2dDataset::Add(double x, double y, double xErrorDelta, double yErrorDelta) [member function]
cls.add_method('Add',
'void',
- [param('double', 'x'), param('double', 'y'), param('double', 'minY'), param('double', 'maxY')])
+ [param('double', 'x'), param('double', 'y'), param('double', 'xErrorDelta'), param('double', 'yErrorDelta')])
## gnuplot.h (module 'tools'): void ns3::Gnuplot2dDataset::AddEmptyLine() [member function]
cls.add_method('AddEmptyLine',
'void',
--- a/src/tools/bindings/modulegen__gcc_LP64.py Sat Aug 20 14:41:19 2011 -0400
+++ b/src/tools/bindings/modulegen__gcc_LP64.py Mon Oct 17 16:59:17 2011 -0400
@@ -1648,10 +1648,10 @@
cls.add_method('Add',
'void',
[param('double', 'x'), param('double', 'y'), param('double', 'errorDelta')])
- ## gnuplot.h (module 'tools'): void ns3::Gnuplot2dDataset::Add(double x, double y, double minY, double maxY) [member function]
+ ## gnuplot.h (module 'tools'): void ns3::Gnuplot2dDataset::Add(double x, double y, double xErrorDelta, double yErrorDelta) [member function]
cls.add_method('Add',
'void',
- [param('double', 'x'), param('double', 'y'), param('double', 'minY'), param('double', 'maxY')])
+ [param('double', 'x'), param('double', 'y'), param('double', 'xErrorDelta'), param('double', 'yErrorDelta')])
## gnuplot.h (module 'tools'): void ns3::Gnuplot2dDataset::AddEmptyLine() [member function]
cls.add_method('AddEmptyLine',
'void',
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tools/examples/gnuplot-example.cc Mon Oct 17 16:59:17 2011 -0400
@@ -0,0 +1,277 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 University of Washington
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mitch Watrous (watrous@u.washington.edu)
+ */
+
+#include <fstream>
+
+#include "ns3/gnuplot.h"
+
+using namespace ns3;
+
+namespace {
+
+//===========================================================================
+// Function: Create2DPlotFile
+//
+//
+// This function creates a 2-D plot file.
+//===========================================================================
+
+void Create2DPlotFile ()
+{
+ using namespace std;
+
+ string fileNameWithNoExtension = "plot-2d";
+ string graphicsFileName = fileNameWithNoExtension + ".png";
+ string plotFileName = fileNameWithNoExtension + ".plt";
+ string plotTitle = "2-D Plot";
+ string dataTitle = "2-D Data";
+
+ // Instantiate the plot and set its title.
+ Gnuplot plot (graphicsFileName);
+ plot.SetTitle (plotTitle);
+
+ // Make the graphics file, which the plot file will create when it
+ // is used with Gnuplot, be a PNG file.
+ plot.SetTerminal ("png");
+
+ // Set the labels for each axis.
+ plot.SetLegend ("X Values", "Y Values");
+
+ // Set the range for the x axis.
+ plot.AppendExtra ("set xrange [-6:+6]");
+
+ // Instantiate the dataset, set its title, and make the points be
+ // plotted along with connecting lines.
+ Gnuplot2dDataset dataset;
+ dataset.SetTitle (dataTitle);
+ dataset.SetStyle (Gnuplot2dDataset::LINES_POINTS);
+
+ double x;
+ double y;
+
+ // Create the 2-D dataset.
+ for (x = -5.0; x <= +5.0; x += 1.0)
+ {
+ // Calculate the 2-D curve
+ //
+ // 2
+ // y = x .
+ //
+ y = x * x;
+
+ // Add this point.
+ dataset.Add (x, y);
+ }
+
+ // Add the dataset to the plot.
+ plot.AddDataset (dataset);
+
+ // Open the plot file.
+ ofstream plotFile (plotFileName.c_str());
+
+ // Write the plot file.
+ plot.GenerateOutput (plotFile);
+
+ // Close the plot file.
+ plotFile.close ();
+}
+
+
+//===========================================================================
+// Function: Create2DPlotWithErrorBarsFile
+//
+//
+// This function creates a 2-D plot with error bars file.
+//===========================================================================
+
+void Create2DPlotWithErrorBarsFile ()
+{
+ using namespace std;
+
+ string fileNameWithNoExtension = "plot-2d-with-error-bars";
+ string graphicsFileName = fileNameWithNoExtension + ".png";
+ string plotFileName = fileNameWithNoExtension + ".plt";
+ string plotTitle = "2-D Plot With Error Bars";
+ string dataTitle = "2-D Data With Error Bars";
+
+ // Instantiate the plot and set its title.
+ Gnuplot plot (graphicsFileName);
+ plot.SetTitle (plotTitle);
+
+ // Make the graphics file, which the plot file will create when it
+ // is used with Gnuplot, be a PNG file.
+ plot.SetTerminal ("png");
+
+ // Set the labels for each axis.
+ plot.SetLegend ("X Values", "Y Values");
+
+ // Set the range for the x axis.
+ plot.AppendExtra ("set xrange [-6:+6]");
+
+ // Instantiate the dataset, set its title, and make the points be
+ // plotted with no connecting lines.
+ Gnuplot2dDataset dataset;
+ dataset.SetTitle (dataTitle);
+ dataset.SetStyle (Gnuplot2dDataset::POINTS);
+
+ // Make the dataset have error bars in both the x and y directions.
+ dataset.SetErrorBars (Gnuplot2dDataset::XY);
+
+ double x;
+ double xErrorDelta;
+ double y;
+ double yErrorDelta;
+
+ // Create the 2-D dataset.
+ for (x = -5.0; x <= +5.0; x += 1.0)
+ {
+ // Calculate the 2-D curve
+ //
+ // 2
+ // y = x .
+ //
+ y = x * x;
+
+ // Make the uncertainty in the x direction be constant and make
+ // the uncertainty in the y direction be a constant fraction of
+ // y's value.
+ xErrorDelta = 0.25;
+ yErrorDelta = 0.1 * y;
+
+ // Add this point with uncertainties in both the x and y
+ // direction.
+ dataset.Add (x, y, xErrorDelta, yErrorDelta);
+ }
+
+ // Add the dataset to the plot.
+ plot.AddDataset (dataset);
+
+ // Open the plot file.
+ ofstream plotFile (plotFileName.c_str());
+
+ // Write the plot file.
+ plot.GenerateOutput (plotFile);
+
+ // Close the plot file.
+ plotFile.close ();
+}
+
+
+//===========================================================================
+// Function: Create3DPlotFile
+//
+//
+// This function creates a 3-D plot file.
+//===========================================================================
+
+void Create3DPlotFile ()
+{
+ using namespace std;
+
+ string fileNameWithNoExtension = "plot-3d";
+ string graphicsFileName = fileNameWithNoExtension + ".png";
+ string plotFileName = fileNameWithNoExtension + ".plt";
+ string plotTitle = "3-D Plot";
+ string dataTitle = "3-D Data";
+
+ // Instantiate the plot and set its title.
+ Gnuplot plot (graphicsFileName);
+ plot.SetTitle (plotTitle);
+
+ // Make the graphics file, which the plot file will create when it
+ // is used with Gnuplot, be a PNG file.
+ plot.SetTerminal ("png");
+
+ // Rotate the plot 30 degrees around the x axis and then rotate the
+ // plot 120 degrees around the new z axis.
+ plot.AppendExtra ("set view 30, 120, 1.0, 1.0");
+
+ // Make the zero for the z-axis be in the x-axis and y-axis plane.
+ plot.AppendExtra ("set ticslevel 0");
+
+ // Set the labels for each axis.
+ plot.AppendExtra ("set xlabel 'X Values'");
+ plot.AppendExtra ("set ylabel 'Y Values'");
+ plot.AppendExtra ("set zlabel 'Z Values'");
+
+ // Set the ranges for the x and y axis.
+ plot.AppendExtra ("set xrange [-5:+5]");
+ plot.AppendExtra ("set yrange [-5:+5]");
+
+ // Instantiate the dataset, set its title, and make the points be
+ // connected by lines.
+ Gnuplot3dDataset dataset;
+ dataset.SetTitle (dataTitle);
+ dataset.SetStyle ("with lines");
+
+ double x;
+ double y;
+ double z;
+
+ // Create the 3-D dataset.
+ for (x = -5.0; x <= +5.0; x += 1.0)
+ {
+ for (y = -5.0; y <= +5.0; y += 1.0)
+ {
+ // Calculate the 3-D surface
+ //
+ // 2 2
+ // z = x * y .
+ //
+ z = x * x * y * y;
+
+ // Add this point.
+ dataset.Add (x, y, z);
+ }
+
+ // The blank line is necessary at the end of each x value's data
+ // points for the 3-D surface grid to work.
+ dataset.AddEmptyLine ();
+ }
+
+ // Add the dataset to the plot.
+ plot.AddDataset (dataset);
+
+ // Open the plot file.
+ ofstream plotFile (plotFileName.c_str());
+
+ // Write the plot file.
+ plot.GenerateOutput (plotFile);
+
+ // Close the plot file.
+ plotFile.close ();
+}
+
+} // anonymous namespace
+
+
+int main (int argc, char *argv[])
+{
+ // Create a 2-D plot file.
+ Create2DPlotFile();
+
+ // Create a 2-D plot with error bars file.
+ Create2DPlotWithErrorBarsFile();
+
+ // Create a 3-D plot file.
+ Create3DPlotFile();
+
+ return 0;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tools/examples/wscript Mon Oct 17 16:59:17 2011 -0400
@@ -0,0 +1,10 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+def build(bld):
+ if not bld.env['ENABLE_EXAMPLES']:
+ return;
+
+ obj = bld.create_ns3_program('gnuplot-example', ['tools'])
+ obj.source = 'gnuplot-example.cc'
+
+
--- a/src/tools/model/gnuplot.cc Sat Aug 20 14:41:19 2011 -0400
+++ b/src/tools/model/gnuplot.cc Mon Oct 17 16:59:17 2011 -0400
@@ -317,17 +317,16 @@
}
void
-Gnuplot2dDataset::Add (double x, double y, double minY, double maxY)
+Gnuplot2dDataset::Add (double x, double y, double xErrorDelta, double yErrorDelta)
{
- NS_ASSERT ( reinterpret_cast<Data2d*>(m_data)->m_errorBars == X ||
- reinterpret_cast<Data2d*>(m_data)->m_errorBars == Y );
+ NS_ASSERT ( reinterpret_cast<Data2d*>(m_data)->m_errorBars == XY );
struct Point data;
data.empty = false;
data.x = x;
data.y = y;
- data.dx = minY;
- data.dy = maxY;
+ data.dx = xErrorDelta;
+ data.dy = yErrorDelta;
reinterpret_cast<Data2d*>(m_data)->m_pointset.push_back (data);
}
--- a/src/tools/model/gnuplot.h Sat Aug 20 14:41:19 2011 -0400
+++ b/src/tools/model/gnuplot.h Mon Oct 17 16:59:17 2011 -0400
@@ -177,7 +177,7 @@
/**
* \param x x coord to new data point
* \param y y coord to new data point
- * \param errorDelta data point error range.
+ * \param errorDelta x and y data point uncertainty
*
* Use this method with error bar style X or Y.
*/
@@ -186,12 +186,12 @@
/**
* \param x x coord to new data point
* \param y y coord to new data point
- * \param minY minimum error data point
- * \param maxY maximum error data point
+ * \param xErrorDelta x data point uncertainty
+ * \param yErrorDelta y data point uncertainty
*
- * Use this method with error bar style X or Y.
+ * Use this method with error bar style XY.
*/
- void Add (double x, double y, double minY, double maxY);
+ void Add (double x, double y, double xErrorDelta, double yErrorDelta);
/**
* Add an empty line in the data output sequence. Empty lines in the plot
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tools/test/examples-to-run.py Mon Oct 17 16:59:17 2011 -0400
@@ -0,0 +1,20 @@
+#! /usr/bin/env python
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+# A list of C++ examples to run in order to ensure that they remain
+# buildable and runnable over time. Each tuple in the list contains
+#
+# (example_name, do_run, do_valgrind_run).
+#
+# See test.py for more information.
+cpp_examples = [
+ ("gnuplot-example", "False", "False"),
+]
+
+# A list of Python examples to run in order to ensure that they remain
+# runnable over time. Each tuple in the list contains
+#
+# (example_name, do_run).
+#
+# See test.py for more information.
+python_examples = []
--- a/src/tools/wscript Sat Aug 20 14:41:19 2011 -0400
+++ b/src/tools/wscript Mon Oct 17 16:59:17 2011 -0400
@@ -14,7 +14,7 @@
'test/event-garbage-collector-test-suite.cc',
]
- headers = bld.new_task_gen('ns3header')
+ headers = bld.new_task_gen(features=['ns3header'])
headers.module = 'tools'
headers.source = [
'model/average.h',
@@ -23,4 +23,7 @@
'model/delay-jitter-estimation.h',
]
+ if (bld.env['ENABLE_EXAMPLES']):
+ bld.add_subdirs('examples')
+
bld.ns3_python_bindings()
--- a/src/topology-read/wscript Sat Aug 20 14:41:19 2011 -0400
+++ b/src/topology-read/wscript Mon Oct 17 16:59:17 2011 -0400
@@ -15,7 +15,7 @@
'test/rocketfuel-topology-reader-test-suite.cc',
]
- headers = bld.new_task_gen('ns3header')
+ headers = bld.new_task_gen(features=['ns3header'])
headers.module = 'topology-read'
headers.source = [
'model/topology-reader.h',
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/uan/model/uan-mac.cc Mon Oct 17 16:59:17 2011 -0400
@@ -0,0 +1,34 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 University of Washington
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mitch Watrous <watrous@u.washington.edu>
+ */
+
+#include "uan-mac.h"
+
+namespace ns3 {
+
+NS_OBJECT_ENSURE_REGISTERED (UanMac);
+
+TypeId UanMac::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::UanMac")
+ .SetParent<Object> ();
+ return tid;
+}
+
+} // namespace ns3
--- a/src/uan/model/uan-mac.h Sat Aug 20 14:41:19 2011 -0400
+++ b/src/uan/model/uan-mac.h Mon Oct 17 16:59:17 2011 -0400
@@ -47,6 +47,8 @@
class UanMac : public Object
{
public:
+ static TypeId GetTypeId (void);
+
/**
* \returns MAC Address
*/
--- a/src/uan/model/uan-noise-model.cc Sat Aug 20 14:41:19 2011 -0400
+++ b/src/uan/model/uan-noise-model.cc Mon Oct 17 16:59:17 2011 -0400
@@ -22,6 +22,15 @@
namespace ns3 {
+NS_OBJECT_ENSURE_REGISTERED (UanNoiseModel);
+
+TypeId UanNoiseModel::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::UanNoiseModel")
+ .SetParent<Object> ();
+ return tid;
+}
+
void
UanNoiseModel::Clear (void)
{
--- a/src/uan/model/uan-noise-model.h Sat Aug 20 14:41:19 2011 -0400
+++ b/src/uan/model/uan-noise-model.h Mon Oct 17 16:59:17 2011 -0400
@@ -28,6 +28,8 @@
class UanNoiseModel : public Object
{
public:
+ static TypeId GetTypeId (void);
+
/**
* \param fKhz Frequency in kHz
* \returns Noise power in dB re 1uPa/Hz
--- a/src/uan/model/uan-phy.cc Sat Aug 20 14:41:19 2011 -0400
+++ b/src/uan/model/uan-phy.cc Mon Oct 17 16:59:17 2011 -0400
@@ -22,6 +22,15 @@
namespace ns3 {
+NS_OBJECT_ENSURE_REGISTERED (UanPhyCalcSinr);
+
+TypeId UanPhyCalcSinr::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::UanPhyCalcSinr")
+ .SetParent<Object> ();
+ return tid;
+}
+
void
UanPhyCalcSinr::Clear ()
{
@@ -34,6 +43,15 @@
Object::DoDispose ();
}
+NS_OBJECT_ENSURE_REGISTERED (UanPhyPer);
+
+TypeId UanPhyPer::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::UanPhyPer")
+ .SetParent<Object> ();
+ return tid;
+}
+
void
UanPhyPer::Clear ()
{
@@ -46,4 +64,13 @@
Object::DoDispose ();
}
+NS_OBJECT_ENSURE_REGISTERED (UanPhy);
+
+TypeId UanPhy::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::UanPhy")
+ .SetParent<Object> ();
+ return tid;
+}
+
} // namespace ns3
--- a/src/uan/model/uan-phy.h Sat Aug 20 14:41:19 2011 -0400
+++ b/src/uan/model/uan-phy.h Mon Oct 17 16:59:17 2011 -0400
@@ -48,6 +48,8 @@
{
public:
+ static TypeId GetTypeId (void);
+
/**
* \param pkt Packet to calculate SINR for
* \param arrTime Arrival time of pkt
@@ -101,6 +103,8 @@
class UanPhyPer : public Object
{
public:
+ static TypeId GetTypeId (void);
+
/**
* Calculates the prob. of packet error based on
* SINR at the receiver and a tx mode.
@@ -167,6 +171,8 @@
class UanPhy : public Object
{
public:
+ static TypeId GetTypeId (void);
+
// / Enum defining possible Phy states
enum State
{
--- a/src/uan/model/uan-prop-model-ideal.cc Sat Aug 20 14:41:19 2011 -0400
+++ b/src/uan/model/uan-prop-model-ideal.cc Mon Oct 17 16:59:17 2011 -0400
@@ -38,7 +38,7 @@
UanPropModelIdeal::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::UanPropModelIdeal")
- .SetParent<Object> ()
+ .SetParent<UanPropModel> ()
.AddConstructor<UanPropModelIdeal> ()
;
return tid;
--- a/src/uan/model/uan-prop-model.cc Sat Aug 20 14:41:19 2011 -0400
+++ b/src/uan/model/uan-prop-model.cc Mon Oct 17 16:59:17 2011 -0400
@@ -336,6 +336,15 @@
return pdp;
}
+NS_OBJECT_ENSURE_REGISTERED (UanPropModel);
+
+TypeId UanPropModel::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::UanPropModel")
+ .SetParent<Object> ();
+ return tid;
+}
+
void
UanPropModel::Clear (void)
{
--- a/src/uan/model/uan-prop-model.h Sat Aug 20 14:41:19 2011 -0400
+++ b/src/uan/model/uan-prop-model.h Mon Oct 17 16:59:17 2011 -0400
@@ -216,6 +216,8 @@
class UanPropModel : public Object
{
public:
+ static TypeId GetTypeId (void);
+
/**
* Computes pathloss between nodes a and b.
* \returns Pathloss in dB re 1 uPa
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/uan/model/uan-transducer.cc Mon Oct 17 16:59:17 2011 -0400
@@ -0,0 +1,34 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 University of Washington
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mitch Watrous <watrous@u.washington.edu>
+ */
+
+#include "uan-transducer.h"
+
+namespace ns3 {
+
+NS_OBJECT_ENSURE_REGISTERED (UanTransducer);
+
+TypeId UanTransducer::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::UanTransducer")
+ .SetParent<Object> ();
+ return tid;
+}
+
+} // namespace ns3
--- a/src/uan/model/uan-transducer.h Sat Aug 20 14:41:19 2011 -0400
+++ b/src/uan/model/uan-transducer.h Mon Oct 17 16:59:17 2011 -0400
@@ -123,6 +123,8 @@
class UanTransducer : public Object
{
public:
+ static TypeId GetTypeId (void);
+
/**
* \brief Transducer state (receiving or transmitting)
*/
--- a/src/uan/wscript Sat Aug 20 14:41:19 2011 -0400
+++ b/src/uan/wscript Mon Oct 17 16:59:17 2011 -0400
@@ -5,6 +5,8 @@
module.source = [
'model/uan-channel.cc',
'model/uan-phy-gen.cc',
+ 'model/uan-mac.cc',
+ 'model/uan-transducer.cc',
'model/uan-transducer-hd.cc',
'model/uan-address.cc',
'model/uan-net-device.cc',
@@ -32,7 +34,7 @@
'test/uan-test.cc',
'test/uan-energy-model-test.cc',
]
- headers = bld.new_task_gen('ns3header')
+ headers = bld.new_task_gen(features=['ns3header'])
headers.module = 'uan'
headers.source = [
'model/uan-channel.h',
--- a/src/virtual-net-device/wscript Sat Aug 20 14:41:19 2011 -0400
+++ b/src/virtual-net-device/wscript Mon Oct 17 16:59:17 2011 -0400
@@ -6,7 +6,7 @@
module.source = [
'model/virtual-net-device.cc',
]
- headers = bld.new_task_gen('ns3header')
+ headers = bld.new_task_gen(features=['ns3header'])
headers.module = 'virtual-net-device'
headers.source = [
'model/virtual-net-device.h',
--- a/src/visualizer/visualizer/base.py Sat Aug 20 14:41:19 2011 -0400
+++ b/src/visualizer/visualizer/base.py Mon Oct 17 16:59:17 2011 -0400
@@ -1,4 +1,12 @@
-import ns3
+import ns.point_to_point
+import ns.csma
+import ns.wifi
+import ns.bridge
+import ns.internet
+import ns.mesh
+import ns.wimax
+import ns.wimax
+
import gobject
import os.path
import sys
@@ -26,14 +34,14 @@
self.is_virtual = is_virtual
netdevice_traits = {
- ns3.PointToPointNetDevice: NetDeviceTraits(is_wireless=False),
- ns3.CsmaNetDevice: NetDeviceTraits(is_wireless=False),
- ns3.WifiNetDevice: NetDeviceTraits(is_wireless=True),
- ns3.BridgeNetDevice: NetDeviceTraits(is_virtual=True),
- ns3.LoopbackNetDevice: NetDeviceTraits(is_virtual=True, is_wireless=False),
- ns3.MeshPointDevice: NetDeviceTraits(is_virtual=True),
- ns3.SubscriberStationNetDevice: NetDeviceTraits(is_wireless=True),
- ns3.BaseStationNetDevice: NetDeviceTraits(is_wireless=True),
+ ns.point_to_point.PointToPointNetDevice: NetDeviceTraits(is_wireless=False),
+ ns.csma.CsmaNetDevice: NetDeviceTraits(is_wireless=False),
+ ns.wifi.WifiNetDevice: NetDeviceTraits(is_wireless=True),
+ ns.bridge.BridgeNetDevice: NetDeviceTraits(is_virtual=True),
+ ns.internet.LoopbackNetDevice: NetDeviceTraits(is_virtual=True, is_wireless=False),
+ ns.mesh.MeshPointDevice: NetDeviceTraits(is_virtual=True),
+ ns.wimax.SubscriberStationNetDevice: NetDeviceTraits(is_wireless=True),
+ ns.wimax.BaseStationNetDevice: NetDeviceTraits(is_wireless=True),
}
def lookup_netdevice_traits(class_type):
--- a/src/visualizer/visualizer/core.py Sat Aug 20 14:41:19 2011 -0400
+++ b/src/visualizer/visualizer/core.py Mon Oct 17 16:59:17 2011 -0400
@@ -20,7 +20,12 @@
SHELL_FONT = "Luxi Mono 10"
-import ns3
+import ns.core
+import ns.network
+import ns.visualizer
+import ns.internet
+import ns.mobility
+
import math
import os
import sys
@@ -154,15 +159,15 @@
def tooltip_query(self, tooltip):
self.visualizer.simulation.lock.acquire()
try:
- ns3_node = ns3.NodeList.GetNode(self.node_index)
- ipv4 = ns3_node.GetObject(ns3.Ipv4.GetTypeId())
- ipv6 = ns3_node.GetObject(ns3.Ipv6.GetTypeId())
+ ns3_node = ns.network.NodeList.GetNode(self.node_index)
+ ipv4 = ns3_node.GetObject(ns.internet.Ipv4.GetTypeId())
+ ipv6 = ns3_node.GetObject(ns.internet.Ipv6.GetTypeId())
lines = ['<b><u>Node %i</u></b>' % self.node_index]
lines.append('')
self.emit("query-extra-tooltip-info", lines)
- mob = ns3_node.GetObject(ns3.MobilityModel.GetTypeId())
+ mob = ns3_node.GetObject(ns.mobility.MobilityModel.GetTypeId())
if mob is not None:
lines.append(' <b>Mobility Model</b>: %s' % mob.GetInstanceTypeId().GetName())
@@ -170,7 +175,7 @@
lines.append('')
lines.append(' <u>NetDevice %i:</u>' % devI)
dev = ns3_node.GetDevice(devI)
- name = ns3.Names.FindName(dev)
+ name = ns.core.Names.FindName(dev)
if name:
lines.append(' <b>Name:</b> %s' % name)
devname = dev.GetInstanceTypeId().GetName()
@@ -296,8 +301,8 @@
@property
def has_mobility(self):
if self._has_mobility is None:
- node = ns3.NodeList.GetNode(self.node_index)
- mobility = node.GetObject(ns3.MobilityModel.GetTypeId())
+ node = ns.network.NodeList.GetNode(self.node_index)
+ mobility = node.GetObject(ns.mobility.MobilityModel.GetTypeId())
self._has_mobility = (mobility is not None)
return self._has_mobility
@@ -352,7 +357,7 @@
self.go.clear()
self.target_time = 0 # in seconds
self.quit = False
- self.sim_helper = ns3.PyViz()
+ self.sim_helper = ns.visualizer.PyViz()
self.pause_messages = []
def set_nodes_of_interest(self, nodes):
@@ -374,13 +379,13 @@
self.lock.acquire()
try:
if 0:
- if ns3.Simulator.IsFinished():
+ if ns3.core.Simulator.IsFinished():
self.viz.play_button.set_sensitive(False)
break
#print "sim: Current time is %f; Run until: %f" % (ns3.Simulator.Now ().GetSeconds (), self.target_time)
#if ns3.Simulator.Now ().GetSeconds () > self.target_time:
# print "skipping, model is ahead of view!"
- self.sim_helper.SimulatorRunUntil(ns3.Seconds(self.target_time))
+ self.sim_helper.SimulatorRunUntil(ns.core.Seconds(self.target_time))
#print "sim: Run until ended at current time: ", ns3.Simulator.Now ().GetSeconds ()
self.pause_messages.extend(self.sim_helper.GetPauseMessages())
gobject.idle_add(self.viz.update_model, priority=PRIORITY_UPDATE_MODEL)
@@ -462,7 +467,7 @@
assert isinstance(mode, ShowTransmissionsMode)
self._show_transmissions_mode = mode
if self._show_transmissions_mode == ShowTransmissionsMode.ALL:
- self.simulation.set_nodes_of_interest(range(ns3.NodeList.GetNNodes()))
+ self.simulation.set_nodes_of_interest(range(ns.network.NodeList.GetNNodes()))
elif self._show_transmissions_mode == ShowTransmissionsMode.NONE:
self.simulation.set_nodes_of_interest([])
elif self._show_transmissions_mode == ShowTransmissionsMode.SELECTED:
@@ -738,19 +743,19 @@
self.window.show()
def scan_topology(self):
- print "scanning topology: %i nodes..." % (ns3.NodeList.GetNNodes(),)
+ print "scanning topology: %i nodes..." % (ns.network.NodeList.GetNNodes(),)
graph = pygraphviz.AGraph()
seen_nodes = 0
- for nodeI in range(ns3.NodeList.GetNNodes()):
+ for nodeI in range(ns.network.NodeList.GetNNodes()):
seen_nodes += 1
if seen_nodes == 100:
- print "scan topology... %i nodes visited (%.1f%%)" % (nodeI, 100*nodeI/ns3.NodeList.GetNNodes())
+ print "scan topology... %i nodes visited (%.1f%%)" % (nodeI, 100*nodeI/ns.network.NodeList.GetNNodes())
seen_nodes = 0
- node = ns3.NodeList.GetNode(nodeI)
+ node = ns.network.NodeList.GetNode(nodeI)
node_name = "Node %i" % nodeI
node_view = self.get_node(nodeI)
- mobility = node.GetObject(ns3.MobilityModel.GetTypeId())
+ mobility = node.GetObject(ns.mobility.MobilityModel.GetTypeId())
if mobility is not None:
node_view.set_color("red")
pos = mobility.GetPosition()
@@ -840,7 +845,7 @@
def update_view(self):
#print "update_view"
- self.time_label.set_text("Time: %f s" % ns3.Simulator.Now().GetSeconds())
+ self.time_label.set_text("Time: %f s" % ns.core.Simulator.Now().GetSeconds())
self._update_node_positions()
@@ -856,8 +861,8 @@
def _update_node_positions(self):
for node in self.nodes.itervalues():
if node.has_mobility:
- ns3_node = ns3.NodeList.GetNode(node.node_index)
- mobility = ns3_node.GetObject(ns3.MobilityModel.GetTypeId())
+ ns3_node = ns.network.NodeList.GetNode(node.node_index)
+ mobility = ns3_node.GetObject(ns.mobility.MobilityModel.GetTypeId())
if mobility is not None:
pos = mobility.GetPosition()
x, y = transform_point_simulation_to_canvas(pos.x, pos.y)
@@ -870,14 +875,14 @@
vadj.value = py - vadj.page_size/2
def center_on_node(self, node):
- if isinstance(node, ns3.Node):
+ if isinstance(node, ns.network.Node):
node = self.nodes[node.GetId()]
elif isinstance(node, (int, long)):
node = self.nodes[node]
elif isinstance(node, Node):
pass
else:
- raise TypeError("expected int, viz.Node or ns3.Node, not %r" % node)
+ raise TypeError("expected int, viz.Node or ns.network.Node, not %r" % node)
x, y = node.get_position()
hadj = self._scrolled_window.get_hadjustment()
@@ -913,7 +918,7 @@
bounds_x1, bounds_y1 = self.canvas.convert_from_pixels(hadj.value, vadj.value)
bounds_x2, bounds_y2 = self.canvas.convert_from_pixels(hadj.value + hadj.page_size,
vadj.value + vadj.page_size)
- pos1_x, pos1_y, pos2_x, pos2_y = ns3.PyViz.LineClipping(bounds_x1, bounds_y1,
+ pos1_x, pos1_y, pos2_x, pos2_y = ns.visualizer.PyViz.LineClipping(bounds_x1, bounds_y1,
bounds_x2, bounds_y2,
pos1_x, pos1_y,
pos2_x, pos2_y)
@@ -1059,7 +1064,7 @@
self.simulation.pause_messages = []
try:
self.update_view()
- self.simulation.target_time = ns3.Simulator.Now ().GetSeconds () + self.sample_period
+ self.simulation.target_time = ns.core.Simulator.Now ().GetSeconds () + self.sample_period
#print "view: target time set to %f" % self.simulation.target_time
finally:
self.simulation.lock.release()
@@ -1209,8 +1214,8 @@
def begin_node_drag(self, node):
self.simulation.lock.acquire()
try:
- ns3_node = ns3.NodeList.GetNode(node.node_index)
- mob = ns3_node.GetObject(ns3.MobilityModel.GetTypeId())
+ ns3_node = ns.network.NodeList.GetNode(node.node_index)
+ mob = ns3_node.GetObject(ns.mobility.MobilityModel.GetTypeId())
if mob is None:
return
if self.node_drag_state is not None:
@@ -1226,8 +1231,8 @@
def node_drag_motion(self, item, targe_item, event, node):
self.simulation.lock.acquire()
try:
- ns3_node = ns3.NodeList.GetNode(node.node_index)
- mob = ns3_node.GetObject(ns3.MobilityModel.GetTypeId())
+ ns3_node = ns.network.NodeList.GetNode(node.node_index)
+ mob = ns3_node.GetObject(ns.mobility.MobilityModel.GetTypeId())
if mob is None:
return False
if self.node_drag_state is None:
@@ -1271,14 +1276,14 @@
else:
self.simulation.lock.acquire()
try:
- ns3_node = ns3.NodeList.GetNode(self.selected_node.node_index)
+ ns3_node = ns.network.NodeList.GetNode(self.selected_node.node_index)
finally:
self.simulation.lock.release()
__IPYTHON__.user_ns['selected_node'] = ns3_node
def select_node(self, node):
- if isinstance(node, ns3.Node):
+ if isinstance(node, ns.network.Node):
node = self.nodes[node.GetId()]
elif isinstance(node, (int, long)):
node = self.nodes[node]
@@ -1287,7 +1292,7 @@
elif node is None:
pass
else:
- raise TypeError("expected None, int, viz.Node or ns3.Node, not %r" % node)
+ raise TypeError("expected None, int, viz.Node or ns.network.Node, not %r" % node)
if node is self.selected_node:
return
@@ -1414,7 +1419,7 @@
surface.finish()
def set_follow_node(self, node):
- if isinstance(node, ns3.Node):
+ if isinstance(node, ns.network.Node):
node = self.nodes[node.GetId()]
self.follow_node = node
@@ -1473,11 +1478,11 @@
if _import_error is not None:
import sys
print >> sys.stderr, "No visualization support (%s)." % (str(_import_error),)
- ns3.Simulator.Run()
+ ns.core.Simulator.Run()
return
load_plugins()
viz = Visualizer()
for hook, args in initialization_hooks:
gobject.idle_add(hook, viz, *args)
- ns3.Packet.EnablePrinting()
+ ns.network.Packet.EnablePrinting()
viz.start()
--- a/src/visualizer/visualizer/plugins/interface_statistics.py Sat Aug 20 14:41:19 2011 -0400
+++ b/src/visualizer/visualizer/plugins/interface_statistics.py Mon Oct 17 16:59:17 2011 -0400
@@ -1,5 +1,6 @@
import gtk
-import ns3
+import ns.core
+import ns.network
from visualizer.base import InformationWindow
NODE_STATISTICS_MEMORY = 10
@@ -125,13 +126,13 @@
self.visualizer.remove_information_window(self)
def update(self):
- node = ns3.NodeList.GetNode(self.node_index)
+ node = ns.network.NodeList.GetNode(self.node_index)
stats_list = self.statistics_collector.get_interface_statistics(self.node_index)
self.table_model.clear()
for iface, stats in enumerate(stats_list):
tree_iter = self.table_model.append()
netdevice = node.GetDevice(iface)
- interface_name = ns3.Names.FindName(netdevice)
+ interface_name = ns.core.Names.FindName(netdevice)
if not interface_name:
interface_name = "(interface %i)" % iface
self.table_model.set(tree_iter,
--- a/src/visualizer/visualizer/plugins/ipv4_routing_table.py Sat Aug 20 14:41:19 2011 -0400
+++ b/src/visualizer/visualizer/plugins/ipv4_routing_table.py Mon Oct 17 16:59:17 2011 -0400
@@ -1,5 +1,9 @@
import gtk
-import ns3
+
+import ns.core
+import ns.network
+import ns.internet
+
from visualizer.base import InformationWindow
class ShowIpv4RoutingTable(InformationWindow):
@@ -66,23 +70,23 @@
self.visualizer.remove_information_window(self)
def update(self):
- node = ns3.NodeList.GetNode(self.node_index)
- ipv4 = node.GetObject(ns3.Ipv4.GetTypeId())
+ node = ns.network.NodeList.GetNode(self.node_index)
+ ipv4 = node.GetObject(ns.internet.Ipv4.GetTypeId())
routing = ipv4.GetRoutingProtocol()
if routing is None:
return
routing_protocols = [] # list of (protocol, type_string, priority)
- if isinstance(routing, ns3.Ipv4StaticRouting):
+ if isinstance(routing, ns.internet.Ipv4StaticRouting):
ipv4_routing = routing_protocols.append((routing, "static", 0))
- elif isinstance(routing, ns3.Ipv4ListRouting):
+ elif isinstance(routing, ns.internet.Ipv4ListRouting):
list_routing = routing
for rI in range(list_routing.GetNRoutingProtocols()):
routing, prio = list_routing.GetRoutingProtocol(rI)
- if isinstance(routing, ns3.Ipv4StaticRouting):
+ if isinstance(routing, ns.internet.Ipv4StaticRouting):
routing_protocols.append((routing, "static", prio))
- elif isinstance(routing, ns3.Ipv4GlobalRouting):
+ elif isinstance(routing, ns.internet.Ipv4GlobalRouting):
routing_protocols.append((routing, "global", prio))
if not routing_protocols:
return
@@ -96,7 +100,7 @@
if netdevice is None:
interface_name = 'lo'
else:
- interface_name = ns3.Names.FindName(netdevice)
+ interface_name = ns.core.Names.FindName(netdevice)
if not interface_name:
interface_name = "(interface %i)" % route.GetInterface()
self.table_model.set(tree_iter,
--- a/src/visualizer/visualizer/plugins/olsr.py Sat Aug 20 14:41:19 2011 -0400
+++ b/src/visualizer/visualizer/plugins/olsr.py Mon Oct 17 16:59:17 2011 -0400
@@ -1,5 +1,10 @@
import gtk
-import ns3
+
+import ns.core
+import ns.network
+import ns.internet
+import ns.olsr
+
from visualizer.base import InformationWindow
class ShowOlsrRoutingTable(InformationWindow):
@@ -60,9 +65,9 @@
self.visualizer.remove_information_window(self)
def update(self):
- node = ns3.NodeList.GetNode(self.node_index)
- olsr = node.GetObject(ns3.olsr.RoutingProtocol.GetTypeId())
- ipv4 = node.GetObject(ns3.Ipv4.GetTypeId())
+ node = ns.network.NodeList.GetNode(self.node_index)
+ olsr = node.GetObject(ns.olsr.olsr.RoutingProtocol.GetTypeId())
+ ipv4 = node.GetObject(ns.internet.Ipv4.GetTypeId())
if olsr is None:
return
self.table_model.clear()
@@ -72,7 +77,7 @@
if netdevice is None:
interface_name = 'lo'
else:
- interface_name = ns3.Names.FindName(netdevice)
+ interface_name = ns.core.Names.FindName(netdevice)
if not interface_name:
interface_name = "(interface %i)" % route.interface
self.table_model.set(tree_iter,
@@ -83,8 +88,8 @@
def populate_node_menu(viz, node, menu):
- ns3_node = ns3.NodeList.GetNode(node.node_index)
- olsr = ns3_node.GetObject(ns3.olsr.RoutingProtocol.GetTypeId())
+ ns3_node = ns.network.NodeList.GetNode(node.node_index)
+ olsr = ns3_node.GetObject(ns.olsr.olsr.RoutingProtocol.GetTypeId())
if olsr is None:
print "No OLSR"
return
--- a/src/visualizer/visualizer/plugins/show_last_packets.py Sat Aug 20 14:41:19 2011 -0400
+++ b/src/visualizer/visualizer/plugins/show_last_packets.py Mon Oct 17 16:59:17 2011 -0400
@@ -1,6 +1,10 @@
import gobject
import gtk
-import ns3
+
+import ns.core
+import ns.network
+import ns.visualizer
+
from visualizer.base import InformationWindow
from visualizer.higcontainer import HIGContainer
from kiwi.ui.objectlist import ObjectList, Column
@@ -39,7 +43,7 @@
if sample.device is None:
interface_name = "(unknown)"
else:
- interface_name = ns3.Names.FindName(sample.device)
+ interface_name = ns.core.Names.FindName(sample.device)
if not interface_name:
interface_name = "(interface %i)" % sample.device.GetIfIndex()
self.table_model.set(tree_iter,
@@ -59,7 +63,7 @@
self.win.set_title("Last packets for node %i" % node_index)
self.visualizer = visualizer
self.viz_node = visualizer.get_node(node_index)
- self.node = ns3.NodeList.GetNode(node_index)
+ self.node = ns.network.NodeList.GetNode(node_index)
def smart_expand(expander, vbox):
if expander.get_expanded():
@@ -102,7 +106,7 @@
# Packet Filter
# - options
- self.packet_capture_options = ns3.PyViz.PacketCaptureOptions()
+ self.packet_capture_options = ns.visualizer.PyViz.PacketCaptureOptions()
self.packet_capture_options.numLastPackets = 100
packet_filter_vbox = gtk.VBox(False, 4)
@@ -129,10 +133,10 @@
self.packet_filter_list = [] # list of TypeIdConfig instances
- Header = ns3.TypeId.LookupByName("ns3::Header")
- Trailer = ns3.TypeId.LookupByName("ns3::Trailer")
- for typeid_i in range(ns3.TypeId.GetRegisteredN()):
- typeid = ns3.TypeId.GetRegistered(typeid_i)
+ Header = ns.core.TypeId.LookupByName("ns3::Header")
+ Trailer = ns.core.TypeId.LookupByName("ns3::Trailer")
+ for typeid_i in range(ns.core.TypeId.GetRegisteredN()):
+ typeid = ns.core.TypeId.GetRegistered(typeid_i)
# check if this is a header or trailer subtype
typeid_tmp = typeid
type_is_good = False
@@ -157,9 +161,9 @@
def update_capture_options():
if self.op_AND_button.props.active:
- self.packet_capture_options.mode = ns3.PyViz.PACKET_CAPTURE_FILTER_HEADERS_AND
+ self.packet_capture_options.mode = ns.visualizer.PyViz.PACKET_CAPTURE_FILTER_HEADERS_AND
else:
- self.packet_capture_options.mode = ns3.PyViz.PACKET_CAPTURE_FILTER_HEADERS_OR
+ self.packet_capture_options.mode = ns.visualizer.PyViz.PACKET_CAPTURE_FILTER_HEADERS_OR
self.packet_capture_options.numLastPackets = 100
self.packet_capture_options.headers = [c.typeid for c in self.packet_filter_list if c.selected]
self.visualizer.simulation.lock.acquire()
--- a/src/visualizer/visualizer/plugins/wifi_intrastructure_link.py Sat Aug 20 14:41:19 2011 -0400
+++ b/src/visualizer/visualizer/plugins/wifi_intrastructure_link.py Mon Oct 17 16:59:17 2011 -0400
@@ -1,5 +1,6 @@
import math
-import ns3
+import ns.wifi
+import ns.network
import goocanvas
from visualizer.base import Link, transform_distance_canvas_to_simulation
@@ -77,17 +78,17 @@
self.stations = []
for node in viz.nodes.itervalues():
- ns3_node = ns3.NodeList.GetNode(node.node_index)
+ ns3_node = ns.network.NodeList.GetNode(node.node_index)
for devI in range(ns3_node.GetNDevices()):
dev = ns3_node.GetDevice(devI)
- if not isinstance(dev, ns3.WifiNetDevice):
+ if not isinstance(dev, ns.wifi.WifiNetDevice):
continue
wifi_mac = dev.GetMac()
- if isinstance(wifi_mac, ns3.StaWifiMac):
+ if isinstance(wifi_mac, ns.wifi.StaWifiMac):
wifi_link = WifiLink(viz.links_group, node, dev)
self.stations.append((dev, node, wifi_link))
- elif isinstance(wifi_mac, ns3.ApWifiMac):
- bssid = ns3.Mac48Address.ConvertFrom(dev.GetAddress())
+ elif isinstance(wifi_mac, ns.wifi.ApWifiMac):
+ bssid = ns.network.Mac48Address.ConvertFrom(dev.GetAddress())
self.access_points[str(bssid)] = node
#print "APs: ", self.access_points
#print "STAs: ", self.stations
--- a/src/visualizer/wscript Sat Aug 20 14:41:19 2011 -0400
+++ b/src/visualizer/wscript Mon Oct 17 16:59:17 2011 -0400
@@ -13,7 +13,7 @@
if 'visualizer' in bld.env['MODULES_NOT_BUILT']:
return
- headers = bld.new_task_gen('ns3header')
+ headers = bld.new_task_gen(features=['ns3header'])
headers.module = 'visualizer'
headers.source = [
]
@@ -36,8 +36,8 @@
return
module.features.append('pyembed')
- module.env.append_value('CXXFLAGS', module.env['shlib_CXXFLAGS'])
- module.includes = '.'
+ #module.env.append_value('CXXFLAGS', module.env['shlib_CXXFLAGS'])
+ #module.includes = '.'
module.source.extend([
'model/pyviz.cc',
--- a/src/wifi/bindings/modulegen__gcc_ILP32.py Sat Aug 20 14:41:19 2011 -0400
+++ b/src/wifi/bindings/modulegen__gcc_ILP32.py Mon Oct 17 16:59:17 2011 -0400
@@ -29,7 +29,7 @@
## wifi-mode.h (module 'wifi'): ns3::WifiModulationClass [enumeration]
module.add_enum('WifiModulationClass', ['WIFI_MOD_CLASS_UNKNOWN', 'WIFI_MOD_CLASS_IR', 'WIFI_MOD_CLASS_FHSS', 'WIFI_MOD_CLASS_DSSS', 'WIFI_MOD_CLASS_ERP_PBCC', 'WIFI_MOD_CLASS_DSSS_OFDM', 'WIFI_MOD_CLASS_ERP_OFDM', 'WIFI_MOD_CLASS_OFDM', 'WIFI_MOD_CLASS_HT'])
## wifi-phy-standard.h (module 'wifi'): ns3::WifiPhyStandard [enumeration]
- module.add_enum('WifiPhyStandard', ['WIFI_PHY_STANDARD_80211a', 'WIFI_PHY_STANDARD_80211b', 'WIFI_PHY_STANDARD_80211g', 'WIFI_PHY_STANDARD_80211_10Mhz', 'WIFI_PHY_STANDARD_80211_5Mhz', 'WIFI_PHY_STANDARD_holland', 'WIFI_PHY_STANDARD_80211p_CCH', 'WIFI_PHY_STANDARD_80211p_SCH'])
+ module.add_enum('WifiPhyStandard', ['WIFI_PHY_STANDARD_80211a', 'WIFI_PHY_STANDARD_80211b', 'WIFI_PHY_STANDARD_80211g', 'WIFI_PHY_STANDARD_80211_10MHZ', 'WIFI_PHY_STANDARD_80211_5MHZ', 'WIFI_PHY_STANDARD_holland', 'WIFI_PHY_STANDARD_80211p_CCH', 'WIFI_PHY_STANDARD_80211p_SCH'])
## qos-tag.h (module 'wifi'): ns3::UserPriority [enumeration]
module.add_enum('UserPriority', ['UP_BK', 'UP_BE', 'UP_EE', 'UP_CL', 'UP_VI', 'UP_VO', 'UP_NC'])
## wifi-mode.h (module 'wifi'): ns3::WifiCodeRate [enumeration]
@@ -3873,9 +3873,9 @@
'uint8_t',
[],
is_const=True)
- ## wifi-mode.h (module 'wifi'): uint32_t ns3::WifiMode::GetDataRate() const [member function]
+ ## wifi-mode.h (module 'wifi'): uint64_t ns3::WifiMode::GetDataRate() const [member function]
cls.add_method('GetDataRate',
- 'uint32_t',
+ 'uint64_t',
[],
is_const=True)
## wifi-mode.h (module 'wifi'): ns3::WifiModulationClass ns3::WifiMode::GetModulationClass() const [member function]
@@ -3883,9 +3883,9 @@
'ns3::WifiModulationClass',
[],
is_const=True)
- ## wifi-mode.h (module 'wifi'): uint32_t ns3::WifiMode::GetPhyRate() const [member function]
+ ## wifi-mode.h (module 'wifi'): uint64_t ns3::WifiMode::GetPhyRate() const [member function]
cls.add_method('GetPhyRate',
- 'uint32_t',
+ 'uint64_t',
[],
is_const=True)
## wifi-mode.h (module 'wifi'): uint32_t ns3::WifiMode::GetUid() const [member function]
--- a/src/wifi/bindings/modulegen__gcc_LP64.py Sat Aug 20 14:41:19 2011 -0400
+++ b/src/wifi/bindings/modulegen__gcc_LP64.py Mon Oct 17 16:59:17 2011 -0400
@@ -29,7 +29,7 @@
## wifi-mode.h (module 'wifi'): ns3::WifiModulationClass [enumeration]
module.add_enum('WifiModulationClass', ['WIFI_MOD_CLASS_UNKNOWN', 'WIFI_MOD_CLASS_IR', 'WIFI_MOD_CLASS_FHSS', 'WIFI_MOD_CLASS_DSSS', 'WIFI_MOD_CLASS_ERP_PBCC', 'WIFI_MOD_CLASS_DSSS_OFDM', 'WIFI_MOD_CLASS_ERP_OFDM', 'WIFI_MOD_CLASS_OFDM', 'WIFI_MOD_CLASS_HT'])
## wifi-phy-standard.h (module 'wifi'): ns3::WifiPhyStandard [enumeration]
- module.add_enum('WifiPhyStandard', ['WIFI_PHY_STANDARD_80211a', 'WIFI_PHY_STANDARD_80211b', 'WIFI_PHY_STANDARD_80211g', 'WIFI_PHY_STANDARD_80211_10Mhz', 'WIFI_PHY_STANDARD_80211_5Mhz', 'WIFI_PHY_STANDARD_holland', 'WIFI_PHY_STANDARD_80211p_CCH', 'WIFI_PHY_STANDARD_80211p_SCH'])
+ module.add_enum('WifiPhyStandard', ['WIFI_PHY_STANDARD_80211a', 'WIFI_PHY_STANDARD_80211b', 'WIFI_PHY_STANDARD_80211g', 'WIFI_PHY_STANDARD_80211_10MHZ', 'WIFI_PHY_STANDARD_80211_5MHZ', 'WIFI_PHY_STANDARD_holland', 'WIFI_PHY_STANDARD_80211p_CCH', 'WIFI_PHY_STANDARD_80211p_SCH'])
## qos-tag.h (module 'wifi'): ns3::UserPriority [enumeration]
module.add_enum('UserPriority', ['UP_BK', 'UP_BE', 'UP_EE', 'UP_CL', 'UP_VI', 'UP_VO', 'UP_NC'])
## wifi-mode.h (module 'wifi'): ns3::WifiCodeRate [enumeration]
@@ -3873,9 +3873,9 @@
'uint8_t',
[],
is_const=True)
- ## wifi-mode.h (module 'wifi'): uint32_t ns3::WifiMode::GetDataRate() const [member function]
+ ## wifi-mode.h (module 'wifi'): uint64_t ns3::WifiMode::GetDataRate() const [member function]
cls.add_method('GetDataRate',
- 'uint32_t',
+ 'uint64_t',
[],
is_const=True)
## wifi-mode.h (module 'wifi'): ns3::WifiModulationClass ns3::WifiMode::GetModulationClass() const [member function]
@@ -3883,9 +3883,9 @@
'ns3::WifiModulationClass',
[],
is_const=True)
- ## wifi-mode.h (module 'wifi'): uint32_t ns3::WifiMode::GetPhyRate() const [member function]
+ ## wifi-mode.h (module 'wifi'): uint64_t ns3::WifiMode::GetPhyRate() const [member function]
cls.add_method('GetPhyRate',
- 'uint32_t',
+ 'uint64_t',
[],
is_const=True)
## wifi-mode.h (module 'wifi'): uint32_t ns3::WifiMode::GetUid() const [member function]
--- a/src/wifi/helper/yans-wifi-helper.cc Sat Aug 20 14:41:19 2011 -0400
+++ b/src/wifi/helper/yans-wifi-helper.cc Mon Oct 17 16:59:17 2011 -0400
@@ -458,7 +458,7 @@
//
// All of the ascii enable functions vector through here including the ones
// that are wandering through all of devices on perhaps all of the nodes in
- // the system. We can only deal with devices of type CsmaNetDevice.
+ // the system. We can only deal with devices of type WifiNetDevice.
//
Ptr<WifiNetDevice> device = nd->GetObject<WifiNetDevice> ();
if (device == 0)
--- a/src/wifi/model/regular-wifi-mac.cc Sat Aug 20 14:41:19 2011 -0400
+++ b/src/wifi/model/regular-wifi-mac.cc Mon Oct 17 16:59:17 2011 -0400
@@ -658,8 +658,8 @@
case WIFI_PHY_STANDARD_holland:
case WIFI_PHY_STANDARD_80211a:
case WIFI_PHY_STANDARD_80211g:
- case WIFI_PHY_STANDARD_80211_10Mhz:
- case WIFI_PHY_STANDARD_80211_5Mhz:
+ case WIFI_PHY_STANDARD_80211_10MHZ:
+ case WIFI_PHY_STANDARD_80211_5MHZ:
cwmin = 15;
cwmax = 1023;
break;
--- a/src/wifi/model/wifi-mac.cc Sat Aug 20 14:41:19 2011 -0400
+++ b/src/wifi/model/wifi-mac.cc Mon Oct 17 16:59:17 2011 -0400
@@ -271,10 +271,10 @@
case WIFI_PHY_STANDARD_80211g:
Configure80211g ();
break;
- case WIFI_PHY_STANDARD_80211_10Mhz:
+ case WIFI_PHY_STANDARD_80211_10MHZ:
Configure80211_10Mhz ();
break;
- case WIFI_PHY_STANDARD_80211_5Mhz:
+ case WIFI_PHY_STANDARD_80211_5MHZ:
Configure80211_5Mhz ();
break;
case WIFI_PHY_STANDARD_holland:
--- a/src/wifi/model/wifi-mode.cc Sat Aug 20 14:41:19 2011 -0400
+++ b/src/wifi/model/wifi-mode.cc Mon Oct 17 16:59:17 2011 -0400
@@ -47,13 +47,13 @@
struct WifiModeFactory::WifiModeItem *item = WifiModeFactory::GetFactory ()->Get (m_uid);
return item->bandwidth;
}
-uint32_t
+uint64_t
WifiMode::GetPhyRate (void) const
{
struct WifiModeFactory::WifiModeItem *item = WifiModeFactory::GetFactory ()->Get (m_uid);
return item->phyRate;
}
-uint32_t
+uint64_t
WifiMode::GetDataRate (void) const
{
struct WifiModeFactory::WifiModeItem *item = WifiModeFactory::GetFactory ()->Get (m_uid);
--- a/src/wifi/model/wifi-mode.h Sat Aug 20 14:41:19 2011 -0400
+++ b/src/wifi/model/wifi-mode.h Mon Oct 17 16:59:17 2011 -0400
@@ -98,11 +98,11 @@
* If a transmission mode uses 1/2 FEC, and if its
* data rate is 3Mbs, the phy rate is 6Mbs
*/
- uint32_t GetPhyRate (void) const;
+ uint64_t GetPhyRate (void) const;
/**
* \returns the data bit rate of this signal.
*/
- uint32_t GetDataRate (void) const;
+ uint64_t GetDataRate (void) const;
/**
* \returns the coding rate of this transmission mode
*/
--- a/src/wifi/model/wifi-phy-standard.h Sat Aug 20 14:41:19 2011 -0400
+++ b/src/wifi/model/wifi-phy-standard.h Mon Oct 17 16:59:17 2011 -0400
@@ -36,9 +36,9 @@
/** ERP-OFDM PHY (Clause 19, Section 19.5) */
WIFI_PHY_STANDARD_80211g,
/** OFDM PHY for the 5 GHz band (Clause 17 with 10 MHz channel bandwidth) */
- WIFI_PHY_STANDARD_80211_10Mhz,
+ WIFI_PHY_STANDARD_80211_10MHZ,
/** OFDM PHY for the 5 GHz band (Clause 17 with 5 MHz channel bandwidth) */
- WIFI_PHY_STANDARD_80211_5Mhz,
+ WIFI_PHY_STANDARD_80211_5MHZ,
/** This is intended to be the configuration used in this paper:
* Gavin Holland, Nitin Vaidya and Paramvir Bahl, "A Rate-Adaptive
* MAC Protocol for Multi-Hop Wireless Networks", in Proc. of
--- a/src/wifi/model/yans-wifi-phy.cc Sat Aug 20 14:41:19 2011 -0400
+++ b/src/wifi/model/yans-wifi-phy.cc Mon Oct 17 16:59:17 2011 -0400
@@ -166,10 +166,10 @@
case WIFI_PHY_STANDARD_80211g:
Configure80211g ();
break;
- case WIFI_PHY_STANDARD_80211_10Mhz:
+ case WIFI_PHY_STANDARD_80211_10MHZ:
Configure80211_10Mhz ();
break;
- case WIFI_PHY_STANDARD_80211_5Mhz:
+ case WIFI_PHY_STANDARD_80211_5MHZ:
Configure80211_5Mhz ();
break;
case WIFI_PHY_STANDARD_holland:
--- a/src/wifi/wscript Sat Aug 20 14:41:19 2011 -0400
+++ b/src/wifi/wscript Mon Oct 17 16:59:17 2011 -0400
@@ -75,7 +75,7 @@
'test/wifi-test.cc',
]
- headers = bld.new_task_gen('ns3header')
+ headers = bld.new_task_gen(features=['ns3header'])
headers.module = 'wifi'
headers.source = [
'model/wifi-information-element.h',
@@ -140,8 +140,8 @@
]
if bld.env['ENABLE_GSL']:
- obj.uselib = 'GSL GSLCBLAS M'
- obj_test.uselib = 'GSL GSLCBLAS M'
+ obj.use.extend(['GSL', 'GSLCBLAS', 'M'])
+ obj_test.use.extend(['GSL', 'GSLCBLAS', 'M'])
if (bld.env['ENABLE_EXAMPLES']):
bld.add_subdirs('examples')
--- a/src/wimax/model/bandwidth-manager.cc Sat Aug 20 14:41:19 2011 -0400
+++ b/src/wimax/model/bandwidth-manager.cc Mon Oct 17 16:59:17 2011 -0400
@@ -37,6 +37,15 @@
namespace ns3 {
+NS_OBJECT_ENSURE_REGISTERED (BandwidthManager);
+
+TypeId BandwidthManager::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::BandwidthManager")
+ .SetParent<Object> ();
+ return tid;
+}
+
BandwidthManager::BandwidthManager (Ptr<WimaxNetDevice> device)
: m_device (device),
m_nrBwReqsSent (0)
--- a/src/wimax/model/bandwidth-manager.h Sat Aug 20 14:41:19 2011 -0400
+++ b/src/wimax/model/bandwidth-manager.h Mon Oct 17 16:59:17 2011 -0400
@@ -54,6 +54,7 @@
class BandwidthManager : public Object
{
public:
+ static TypeId GetTypeId (void);
BandwidthManager (Ptr<WimaxNetDevice> device);
~BandwidthManager (void);
void DoDispose (void);
--- a/src/wimax/model/bs-link-manager.cc Sat Aug 20 14:41:19 2011 -0400
+++ b/src/wimax/model/bs-link-manager.cc Mon Oct 17 16:59:17 2011 -0400
@@ -36,7 +36,14 @@
namespace ns3 {
-NS_OBJECT_ENSURE_REGISTERED ( BSLinkManager);
+NS_OBJECT_ENSURE_REGISTERED (BSLinkManager);
+
+TypeId BSLinkManager::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::BSLinkManager")
+ .SetParent<Object> ();
+ return tid;
+}
BSLinkManager::BSLinkManager (Ptr<BaseStationNetDevice> bs)
: m_bs (bs),
--- a/src/wimax/model/bs-link-manager.h Sat Aug 20 14:41:19 2011 -0400
+++ b/src/wimax/model/bs-link-manager.h Mon Oct 17 16:59:17 2011 -0400
@@ -38,6 +38,7 @@
class BSLinkManager : public Object
{
public:
+ static TypeId GetTypeId (void);
BSLinkManager (Ptr<BaseStationNetDevice> bs);
~BSLinkManager (void);
/**
--- a/src/wimax/model/burst-profile-manager.cc Sat Aug 20 14:41:19 2011 -0400
+++ b/src/wimax/model/burst-profile-manager.cc Mon Oct 17 16:59:17 2011 -0400
@@ -31,6 +31,15 @@
namespace ns3 {
+NS_OBJECT_ENSURE_REGISTERED (BurstProfileManager);
+
+TypeId BurstProfileManager::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::BurstProfileManager")
+ .SetParent<Object> ();
+ return tid;
+}
+
BurstProfileManager::BurstProfileManager (Ptr<WimaxNetDevice> device)
: m_device (device)
{
--- a/src/wimax/model/burst-profile-manager.h Sat Aug 20 14:41:19 2011 -0400
+++ b/src/wimax/model/burst-profile-manager.h Mon Oct 17 16:59:17 2011 -0400
@@ -37,6 +37,7 @@
class BurstProfileManager : public Object
{
public:
+ static TypeId GetTypeId (void);
BurstProfileManager (Ptr<WimaxNetDevice> device);
~BurstProfileManager (void);
void DoDispose (void);
--- a/src/wimax/model/connection-manager.cc Sat Aug 20 14:41:19 2011 -0400
+++ b/src/wimax/model/connection-manager.cc Mon Oct 17 16:59:17 2011 -0400
@@ -35,6 +35,15 @@
namespace ns3 {
+NS_OBJECT_ENSURE_REGISTERED (ConnectionManager);
+
+TypeId ConnectionManager::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::ConnectionManager")
+ .SetParent<Object> ();
+ return tid;
+}
+
ConnectionManager::ConnectionManager (void)
: m_cidFactory (0)
{
--- a/src/wimax/model/connection-manager.h Sat Aug 20 14:41:19 2011 -0400
+++ b/src/wimax/model/connection-manager.h Mon Oct 17 16:59:17 2011 -0400
@@ -44,6 +44,7 @@
class ConnectionManager : public Object
{
public:
+ static TypeId GetTypeId (void);
ConnectionManager (void);
~ConnectionManager (void);
void DoDispose (void);
--- a/src/wimax/model/ipcs-classifier.cc Sat Aug 20 14:41:19 2011 -0400
+++ b/src/wimax/model/ipcs-classifier.cc Mon Oct 17 16:59:17 2011 -0400
@@ -35,6 +35,15 @@
namespace ns3 {
+NS_OBJECT_ENSURE_REGISTERED (IpcsClassifier);
+
+TypeId IpcsClassifier::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::IpcsClassifier")
+ .SetParent<Object> ();
+ return tid;
+}
+
IpcsClassifier::IpcsClassifier (void)
{
}
--- a/src/wimax/model/ipcs-classifier.h Sat Aug 20 14:41:19 2011 -0400
+++ b/src/wimax/model/ipcs-classifier.h Mon Oct 17 16:59:17 2011 -0400
@@ -37,6 +37,7 @@
class IpcsClassifier : public Object
{
public:
+ static TypeId GetTypeId (void);
IpcsClassifier (void);
~IpcsClassifier (void);
/**
--- a/src/wimax/model/service-flow-manager.cc Sat Aug 20 14:41:19 2011 -0400
+++ b/src/wimax/model/service-flow-manager.cc Mon Oct 17 16:59:17 2011 -0400
@@ -43,6 +43,15 @@
namespace ns3 {
+NS_OBJECT_ENSURE_REGISTERED (ServiceFlowManager);
+
+TypeId ServiceFlowManager::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::ServiceFlowManager")
+ .SetParent<Object> ();
+ return tid;
+}
+
ServiceFlowManager::ServiceFlowManager ()
{
m_serviceFlows = new std::vector<ServiceFlow*>;
--- a/src/wimax/model/service-flow-manager.h Sat Aug 20 14:41:19 2011 -0400
+++ b/src/wimax/model/service-flow-manager.h Mon Oct 17 16:59:17 2011 -0400
@@ -47,6 +47,8 @@
CONFIRMATION_CODE_SUCCESS, CONFIRMATION_CODE_REJECT
};
+ static TypeId GetTypeId (void);
+
ServiceFlowManager ();
~ServiceFlowManager (void);
void DoDispose (void);
--- a/src/wimax/model/ss-link-manager.cc Sat Aug 20 14:41:19 2011 -0400
+++ b/src/wimax/model/ss-link-manager.cc Mon Oct 17 16:59:17 2011 -0400
@@ -35,6 +35,15 @@
namespace ns3 {
+NS_OBJECT_ENSURE_REGISTERED (SSLinkManager);
+
+TypeId SSLinkManager::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::SSLinkManager")
+ .SetParent<Object> ();
+ return tid;
+}
+
SSLinkManager::SSLinkManager (Ptr<SubscriberStationNetDevice> ss)
: m_ss (ss),
m_rangingStatus (WimaxNetDevice::RANGING_STATUS_EXPIRED),
--- a/src/wimax/model/ss-link-manager.h Sat Aug 20 14:41:19 2011 -0400
+++ b/src/wimax/model/ss-link-manager.h Mon Oct 17 16:59:17 2011 -0400
@@ -41,6 +41,7 @@
class SSLinkManager : public Object
{
public:
+ static TypeId GetTypeId (void);
SSLinkManager (Ptr<SubscriberStationNetDevice> ss);
~SSLinkManager (void);
void DoDispose (void);
--- a/src/wimax/model/ss-manager.cc Sat Aug 20 14:41:19 2011 -0400
+++ b/src/wimax/model/ss-manager.cc Mon Oct 17 16:59:17 2011 -0400
@@ -28,7 +28,14 @@
NS_LOG_COMPONENT_DEFINE ("SSManager");
namespace ns3 {
-NS_OBJECT_ENSURE_REGISTERED ( SSManager);
+NS_OBJECT_ENSURE_REGISTERED (SSManager);
+
+TypeId SSManager::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::SSManager")
+ .SetParent<Object> ();
+ return tid;
+}
SSManager::SSManager (void)
{
--- a/src/wimax/model/ss-manager.h Sat Aug 20 14:41:19 2011 -0400
+++ b/src/wimax/model/ss-manager.h Mon Oct 17 16:59:17 2011 -0400
@@ -37,6 +37,7 @@
class SSManager : public Object
{
public:
+ static TypeId GetTypeId (void);
SSManager (void);
~SSManager (void);
SSRecord* CreateSSRecord (const Mac48Address &macAddress);
--- a/src/wimax/model/ss-scheduler.cc Sat Aug 20 14:41:19 2011 -0400
+++ b/src/wimax/model/ss-scheduler.cc Mon Oct 17 16:59:17 2011 -0400
@@ -36,6 +36,13 @@
namespace ns3 {
NS_OBJECT_ENSURE_REGISTERED (SSScheduler);
+TypeId SSScheduler::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::SSScheduler")
+ .SetParent<Object> ();
+ return tid;
+}
+
SSScheduler::SSScheduler (Ptr<SubscriberStationNetDevice> ss)
: m_ss (ss),
m_pollMe (false)
--- a/src/wimax/model/ss-scheduler.h Sat Aug 20 14:41:19 2011 -0400
+++ b/src/wimax/model/ss-scheduler.h Mon Oct 17 16:59:17 2011 -0400
@@ -41,6 +41,7 @@
{
public:
+ static TypeId GetTypeId (void);
SSScheduler (Ptr<SubscriberStationNetDevice> ss);
~SSScheduler (void);
--- a/src/wimax/model/wimax-channel.cc Sat Aug 20 14:41:19 2011 -0400
+++ b/src/wimax/model/wimax-channel.cc Mon Oct 17 16:59:17 2011 -0400
@@ -27,6 +27,15 @@
namespace ns3 {
+NS_OBJECT_ENSURE_REGISTERED (WimaxChannel);
+
+TypeId WimaxChannel::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::WimaxChannel")
+ .SetParent<Channel> ();
+ return tid;
+}
+
WimaxChannel::WimaxChannel (void)
{
}
--- a/src/wimax/model/wimax-channel.h Sat Aug 20 14:41:19 2011 -0400
+++ b/src/wimax/model/wimax-channel.h Mon Oct 17 16:59:17 2011 -0400
@@ -39,6 +39,7 @@
class WimaxChannel : public Channel
{
public:
+ static TypeId GetTypeId (void);
WimaxChannel (void);
virtual ~WimaxChannel (void);
/**
--- a/src/wimax/wscript Sat Aug 20 14:41:19 2011 -0400
+++ b/src/wimax/wscript Mon Oct 17 16:59:17 2011 -0400
@@ -1,6 +1,6 @@
## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
def build(bld):
- obj = bld.create_ns3_module('wimax', ['network', 'spectrum', 'point-to-point'])
+ obj = bld.create_ns3_module('wimax', ['network', 'point-to-point', 'internet', 'applications', 'propagation', 'mobility'])
obj.source = [
'model/cid.cc',
'model/cid-factory.cc',
@@ -63,7 +63,7 @@
'test/wimax-fragmentation-test.cc',
]
- headers = bld.new_task_gen('ns3header')
+ headers = bld.new_task_gen(features=['ns3header'])
headers.module = 'wimax'
headers.source = [
'model/wimax-channel.h',
--- a/src/wscript Sat Aug 20 14:41:19 2011 -0400
+++ b/src/wscript Mon Oct 17 16:59:17 2011 -0400
@@ -6,15 +6,13 @@
import types
import warnings
+from waflib.Errors import WafError
+
import TaskGen
import Task
import Options
import Build
import Utils
-import Constants
-
-import ccroot
-ccroot.USE_TOP_LEVEL = True
import wutils
@@ -23,53 +21,21 @@
except NameError:
from sets import Set as set # Python 2.3 fallback
-all_modules = [
- 'core',
- 'network',
- 'config-store',
- 'internet',
- 'propagation',
- 'point-to-point',
- 'csma',
- 'emu',
- 'bridge',
- 'tap-bridge',
- 'virtual-net-device',
- 'applications',
- 'nix-vector-routing',
- 'olsr',
- 'aodv',
- 'dsdv',
- 'click',
- 'openflow',
- 'mobility',
- 'wifi',
- 'netanim',
- 'stats',
- 'uan',
- 'spectrum',
- 'mesh',
- 'test',
- 'test/ns3tcp',
- 'test/ns3wifi',
- 'flow-monitor',
- 'wimax',
- 'lte',
- 'mpi',
- 'topology-read',
- 'energy',
- 'tools',
- 'visualizer',
- 'point-to-point-layout',
- 'csma-layout',
- 'template',
- ]
-def set_options(opt):
- opt.sub_options('core')
- opt.sub_options('click')
- opt.sub_options('openflow')
+all_modules = []
+for dirname in os.listdir('src'):
+ if dirname.startswith('.') or dir == 'CVS':
+ continue
+ path = os.path.join('src', dirname)
+ if not os.path.isdir(path):
+ continue
+ if os.path.exists(os.path.join(path, 'wscript')):
+ all_modules.append(dirname)
+all_modules.sort()
+
+
+def options(opt):
opt.add_option('--enable-rpath',
help=("Link programs with rpath"
" (normally not needed, see "
@@ -81,20 +47,15 @@
help=("Build only these modules (and dependencies)"),
dest='enable_modules')
+ for module in all_modules:
+ opt.sub_options(module, mandatory=False)
+
+
def configure(conf):
- conf.sub_config('core')
- conf.sub_config('emu')
- conf.sub_config('tap-bridge')
- conf.sub_config('config-store')
- conf.sub_config('internet')
- conf.sub_config('netanim')
- conf.sub_config('test')
- conf.sub_config('click')
- conf.sub_config('openflow')
- conf.sub_config('stats')
- conf.sub_config('visualizer')
+ for module in all_modules:
+ conf.sub_config(module, mandatory=False)
- blddir = os.path.abspath(os.path.join(conf.blddir, conf.env.variant()))
+ blddir = os.path.abspath(os.path.join(conf.bldnode.abspath(), conf.variant))
conf.env.append_value('NS3_MODULE_PATH', blddir)
if Options.options.enable_rpath:
conf.env.append_value('RPATH', '-Wl,-rpath=%s' % (os.path.join(blddir),))
@@ -103,176 +64,85 @@
conf.env['NS3_MODULES'] = ['ns3-' + module.split('/')[-1] for module in all_modules]
-class ns3module_taskgen(TaskGen.task_gen):
- def __init__(self, *args, **kwargs):
- super(ns3module_taskgen, self).__init__(*args, **kwargs)
- self.libs = []
- def apply(self):
- static_enabled = False
- shared_enabled = True
- bld = self.bld
- if bld.env['ENABLE_STATIC_NS3']:
- static_enabled = True
- shared_enabled = False
- if bld.env['ENABLE_SHARED_AND_STATIC_NS3']:
- static_enabled = True
- shared_enabled = True
-
- assert self.name.startswith("ns3-")
- name = self.name.split("ns3-")[1]
-
- if static_enabled:
- static = self._create_ns3_module(self.bld, name, self.dependencies, True)
- self.libs.append(static)
- else:
- static = None
-
- if shared_enabled:
- shared = self._create_ns3_module(self.bld, name, self.dependencies, False)
- self.libs.append(shared)
- else:
- shared = None
-
- if static is not None and shared is None:
- static.name = self.name + "--lib"
- static.uselib_local = ['ns3-%s--lib' % (dep,) for dep in self.dependencies]
-
- elif shared is not None and static is None:
- shared.name = self.name + "--lib"
- shared.uselib_local = ['ns3-%s--lib' % (dep,) for dep in self.dependencies]
- else:
- shared.name = self.name + "--lib"
- shared.uselib_local = ['ns3-%s--lib' % (dep,) for dep in self.dependencies]
- static.name = self.name + "--static"
- static.uselib_local = ['ns3-%s--static' % (dep,) for dep in self.dependencies]
-
- if not self.test:
- pcfile = bld.new_task_gen('ns3pcfile')
- pcfile.module = self
-
- def _create_ns3_module(self, bld, name, dependencies, static):
-
- # FIXME: env modifications are overwritten by parent caller
-
- # Create a separate library for this module.
- if static:
- module = bld.new_task_gen('cxx', 'cstaticlib')
- else:
- module = bld.new_task_gen('cxx', 'cshlib')
-
- module.source = self.source
- module.env = self.env.copy()
- features = list(self.features)
- features.remove("ns3module")
- module.features.extend(features)
- module.path = self.path
- module.uselib = self.uselib
- module.target = 'ns3-' + name
- if hasattr(self, 'includes'):
- module.includes = self.includes
- if hasattr(self, 'defines'):
- module.defines = self.defines
- else:
- module.defines = []
- if hasattr(self, 'add_objects'):
- module.add_objects = self.add_objects
- else:
- module.add_objects = []
- if hasattr(self, "is_ns3_module"):
- module.is_ns3_module = self.is_ns3_module
- if hasattr(self, 'add_objects'):
- module.add_objects = self.add_objects
-
- linkflags = []
- cxxflags = []
- ccflags = []
- if not static:
- cxxflags = module.env['shlib_CXXFLAGS']
- ccflags = module.env['shlib_CXXFLAGS']
- # Turn on the link flags for shared libraries if we have the
- # proper compiler and platform.
- if module.env['CXX_NAME'] in ['gcc', 'icc'] and module.env['WL_SONAME_SUPPORTED']:
- # Get the module library name without any relative paths
- # at its beginning because all of the libraries will end
- # up in the same directory.
- module_library_name = os.path.basename(ccroot.get_target_name(module))
- linkflags = '-Wl,--soname=%s' % module_library_name
- elif module.env['CXX_NAME'] in ['gcc', 'icc'] and \
- os.uname()[4] == 'x86_64' and \
- module.env['ENABLE_PYTHON_BINDINGS']:
- # enable that flag for static builds only on x86-64 platforms
- # when gcc is present and only when we want python bindings
- # (it's more efficient to not use this option if we can avoid it)
- cxxflags = ['-mcmodel=large']
- ccflags = ['-mcmodel=large']
- cxxdefines = ["NS3_MODULE_COMPILATION"]
- ccdefines = ["NS3_MODULE_COMPILATION"]
-
- module.env.append_value('CXXFLAGS', cxxflags)
- module.env.append_value('CCFLAGS', ccflags)
- module.env.append_value('LINKFLAGS', linkflags)
- module.env.append_value('CXXDEFINES', cxxdefines)
- module.env.append_value('CCDEFINES', ccdefines)
-
- if len(module.source) > 0 and hasattr(self, 'ns3_dir_location'):
- uselib_cpppath = []
- for lib in module.uselib.split():
- if 'CPPPATH_%s' % lib in module.env:
- uselib_cpppath.extend(module.env['CPPPATH_%s' % lib])
- objects = []
- for src in module.source[0:-1]:
- full_src = os.path.join(self.ns3_dir_location, src)
- path = os.path.dirname(full_src)
- target = '%s_object' % src
- # XXX: calculate the features correctly here.
- obj = bld (source=[full_src], target=target, features='cxx cc',
- defines=['NS_TEST_SOURCEDIR="%s"' % path],
- includes=' '.join(uselib_cpppath),
- env = module.env)
- objects.append(target)
- last = module.source[-1]
- full_src = os.path.join(self.ns3_dir_location, last)
- path = os.path.dirname(full_src)
- module.defines.append('NS_TEST_SOURCEDIR="%s"' % path)
- module.source = [last]
- module.add_objects.extend(objects)
-
-
- module.is_static = static
- module.vnum = wutils.VNUM
- # Add the proper path to the module's name.
- module.target = '%s/ns3-%s' % (bld.srcnode.relpath_gen(self.path), name)
- # Set the libraries this module depends on.
- module.module_deps = list(dependencies)
-
- module.install_path = "${LIBDIR}"
-
- return module
+# we need the 'ns3module' waf "feature" to be created because code
+# elsewhere looks for it to find the ns3 module objects.
+@TaskGen.feature('ns3module')
+def _add_test_code(module):
+ pass
def create_ns3_module(bld, name, dependencies=(), test=False):
- module = bld.new_task_gen('ns3module')
- module.bld = bld
+ static = bool(bld.env.ENABLE_STATIC_NS3)
+ # Create a separate library for this module.
+ if static:
+ module = bld.new_task_gen(features=['cxx', 'cxxstlib', 'ns3module'])
+ else:
+ module = bld.new_task_gen(features=['cxx', 'cxxshlib', 'ns3module'])
+ module.target = '%s/ns3-%s' % (bld.srcnode.relpath_gen(module.path), name)
+ linkflags = []
+ cxxflags = []
+ ccflags = []
+ if not static:
+ cxxflags = module.env['shlib_CXXFLAGS']
+ ccflags = module.env['shlib_CXXFLAGS']
+ # Turn on the link flags for shared libraries if we have the
+ # proper compiler and platform.
+ if module.env['CXX_NAME'] in ['gcc', 'icc'] and module.env['WL_SONAME_SUPPORTED']:
+ # Get the module library name without any relative paths
+ # at its beginning because all of the libraries will end
+ # up in the same directory.
+ module_library_name = module.env.cshlib_PATTERN % (os.path.basename(module.target),)
+ linkflags = '-Wl,--soname=' + module_library_name
+ cxxdefines = ["NS3_MODULE_COMPILATION"]
+ ccdefines = ["NS3_MODULE_COMPILATION"]
+
+ module.env.append_value('CXXFLAGS', cxxflags)
+ module.env.append_value('CCFLAGS', ccflags)
+ module.env.append_value('LINKFLAGS', linkflags)
+ module.env.append_value('CXXDEFINES', cxxdefines)
+ module.env.append_value('CCDEFINES', ccdefines)
+
+ module.is_static = static
+ module.vnum = wutils.VNUM
+ # Add the proper path to the module's name.
+ # Set the libraries this module depends on.
+ module.module_deps = list(dependencies)
+
+ module.install_path = "${LIBDIR}"
+
module.name = "ns3-" + name
module.dependencies = dependencies
# Initially create an empty value for this because the pcfile
# writing task assumes every module has a uselib attribute.
module.uselib = ''
- module.uselib_local = ['ns3-' + dep for dep in dependencies]
- module.module_deps = list(dependencies)
+ module.use = ['ns3-' + dep for dep in dependencies]
module.test = test
module.is_ns3_module = True
module.ns3_dir_location = bld.path.relpath_gen(bld.srcnode)
+ module.env.append_value("INCLUDES", '#')
+
+ pcfilegen = bld(features='ns3pcfile')
+ pcfilegen.module = module
+
return module
+@TaskGen.feature("ns3testlib")
+@TaskGen.before_method("apply_incpaths")
+def apply_incpaths_ns3testlib(self):
+ if not self.source:
+ return
+ testdir = self.source[-1].parent.relpath_gen(self.bld.srcnode)
+ self.env.append_value("DEFINES", 'NS_TEST_SOURCEDIR="%s"' % (testdir,))
+
def create_ns3_module_test_library(bld, name):
# Create an ns3 module for the test library that depends only on
# the module being tested.
library_name = name + "-test"
- library = bld.create_ns3_module(library_name, [name], test = True)
+ library = bld.create_ns3_module(library_name, [name], test=True)
+ library.features.append("ns3testlib")
# Modify attributes for the test library that are different from a
# normal module.
@@ -281,7 +151,7 @@
library.module_name = 'ns3-' + name
# Add this module and test library to the list.
- bld.env.append_value('NS3_MODULES_WITH_TEST_LIBRARIES', (library.module_name, library.name))
+ bld.env.append_value('NS3_MODULES_WITH_TEST_LIBRARIES', [(library.module_name, library.name)])
# Set the include path from the build directory to modules.
relative_path_from_build_to_here = bld.path.relpath_gen(bld.bldnode)
@@ -298,6 +168,9 @@
def ns3_python_bindings(bld):
+ if Options.options.apiscan:
+ return
+
# this method is called from a module wscript, so remember bld.path is not bindings/python!
module_abs_src_path = bld.path.abspath()
module = os.path.basename(module_abs_src_path)
@@ -366,40 +239,41 @@
if was_enabled:
features.append(name)
- bindgen = bld.new_task_gen('command', source=source, target=target, command=argv)
+ bindgen = bld.new_task_gen(features=['command'], source=source, target=target, command=argv)
bindgen.env['FEATURES'] = ','.join(features)
bindgen.dep_vars = ['FEATURES', "GCC_RTTI_ABI_COMPLETE"]
bindgen.before = 'cxx'
- bindgen.after = 'gen_ns3_module_header_task'
+ bindgen.after = 'gen_ns3_module_header'
bindgen.name = "pybindgen(ns3 module %s)" % module
+ bindgen.install_path = None
# generate the extension module
- pymod = bld.new_task_gen(features='cxx cshlib pyext')
+ pymod = bld.new_task_gen(features='cxx cxxshlib pyext')
pymod.source = ['bindings/ns3module.cc']
pymod.target = '%s/%s' % (module_target_dir, extension_name)
pymod.name = 'ns3module_%s' % module
- pymod.uselib_local = ["%s--lib" % mod for mod in pymod.env['NS3_ENABLED_MODULES']] # Should be '"ns3-"+module', but see bug 1117
+ pymod.use = ["%s" % mod for mod in pymod.env['NS3_ENABLED_MODULES']] # Should be '"ns3-"+module', but see bug 1117
if pymod.env['ENABLE_STATIC_NS3']:
if sys.platform == 'darwin':
pymod.env.append_value('LINKFLAGS', '-Wl,-all_load')
- for mod in pymod.uselib_local:
- mod = mod.split("--lib")[0]
+ for mod in pymod.usel:
+ #mod = mod.split("--lib")[0]
pymod.env.append_value('LINKFLAGS', '-l' + mod)
else:
pymod.env.append_value('LINKFLAGS', '-Wl,--whole-archive,-Bstatic')
- for mod in pymod.uselib_local:
- mod = mod.split("--lib")[0]
+ for mod in pymod.use:
+ #mod = mod.split("--lib")[0]
pymod.env.append_value('LINKFLAGS', '-l' + mod)
pymod.env.append_value('LINKFLAGS', '-Wl,-Bdynamic,--no-whole-archive')
- defines = list(pymod.env['CXXDEFINES'])
+ defines = list(pymod.env['DEFINES'])
defines.extend(['NS_DEPRECATED=', 'NS3_DEPRECATED_H'])
if Options.platform == 'win32':
try:
defines.remove('_DEBUG') # causes undefined symbols on win32
except ValueError:
pass
- pymod.env['CXXDEFINES'] = defines
- pymod.includes = 'bindings'
+ pymod.env['DEFINES'] = defines
+ pymod.includes = '# bindings'
pymod.install_path = '${PYTHONDIR}/ns'
return pymod
@@ -426,30 +300,35 @@
bld.add_subdirs(list(all_modules))
for module in all_modules:
- modheader = bld.new_task_gen('ns3moduleheader')
+ modheader = bld.new_task_gen(features=['ns3moduleheader'])
modheader.module = module.split('/')[-1]
class ns3pcfile_task(Task.Task):
after = 'cc cxx'
+
def __str__(self):
"string to display to the user"
tgt_str = ' '.join([a.nice_path(self.env) for a in self.outputs])
return 'pcfile: %s\n' % (tgt_str)
+
def runnable_status(self):
return super(ns3pcfile_task, self).runnable_status()
+
def _self_libs(self, env, name, libdir):
if env['ENABLE_STATIC_NS3']:
- path_st = 'STATICLIBPATH_ST'
- lib_st = 'STATICLIB_ST'
- lib_marker = 'STATICLIB_MARKER'
+ path_st = 'STLIBPATH_ST'
+ lib_st = 'STLIB_ST'
+ lib_marker = 'STLIB_MARKER'
else:
path_st = 'LIBPATH_ST'
lib_st = 'LIB_ST'
lib_marker = 'SHLIB_MARKER'
- retval = [env[path_st] % libdir,
- env[lib_marker],
- env[lib_st] % name]
+ retval = [env[path_st] % libdir]
+ if env[lib_marker]:
+ retval.append(env[lib_marker])
+ retval.append(env[lib_st] % name)
return retval
+
def _lib(self, env, dep):
libpath = env['LIBPATH_%s' % dep]
linkflags = env['LINKFLAGS_%s' % dep]
@@ -461,38 +340,44 @@
for lib in libs:
retval.append(env['LIB_ST'] % lib)
return retval
+
def _listify(self, v):
if isinstance(v, list):
return v
else:
return [v]
+
def _cflags(self, dep):
flags = self.env['CFLAGS_%s' % dep]
return self._listify(flags)
+
def _cxxflags(self, dep):
return self._listify(self.env['CXXFLAGS_%s' % dep])
+
def _defines(self, dep):
- defines = self.env['CCDEFINES_%s' % dep] + self.env['CXXDEFINES_%s' % dep]
- return [self.env['CCDEFINES_ST'] % define for define in self.env['CCDEFINES_%s' % dep]] + \
- [self.env['CXXDEFINES_ST'] % define for define in self.env['CXXDEFINES_%s' % dep]]
+ return [self.env['DEFINES_ST'] % define for define in self.env['DEFINES_%s' % dep]]
+
def _includes(self, dep):
- includes = self.env['CPPPATH_%s' % dep]
+ includes = self.env['INCLUDES_%s' % dep]
return [self.env['CPPPATH_ST'] % include for include in includes]
- def _generate_pcfile(self, name, use, uselib_local, env, outfilename):
- outfile = open(outfilename, 'w')
+ def _generate_pcfile(self, name, use, env, outfilename):
+ outfile = open(outfilename, 'wt')
prefix = env.PREFIX
includedir = env.INCLUDEDIR
libdir = env.LIBDIR
- libs = self._self_libs(self.env, name, '${libdir}')
+ libs = self._self_libs(env, name, '${libdir}')
for dep in use:
- libs = libs + self._lib(self.env, dep)
- for dep in uselib_local:
- libs = libs + [self.env['LIB_ST'] % dep]
+ libs += self._lib(env, dep)
+ for dep in env.LIBS:
+ libs += self.env['LIB_ST'] % dep
cflags = [self.env['CPPPATH_ST'] % '${includedir}']
+ requires = []
for dep in use:
cflags = cflags + self._cflags(dep) + self._cxxflags(dep) + \
self._defines(dep) + self._includes(dep)
+ if dep.startswith('ns3-'):
+ requires.append("lib"+dep)
print >> outfile, """
prefix=%s
libdir=%s
@@ -503,64 +388,57 @@
Version: devel
Libs: %s
Cflags: %s
+Requires: %s
""" % (prefix, libdir, includedir,
- name, name, ' '.join(libs), ' '.join(cflags))
+ name, name, ' '.join(libs), ' '.join(cflags), ' '.join(requires))
outfile.close()
def run(self):
- output_filename = self.outputs[0].bldpath(self.env)
- self._generate_pcfile(self.module.name, self.module.uselib,
- self.module.uselib_local,
+ output_filename = self.outputs[0].abspath()
+ self._generate_pcfile(self.module.name,
+ self.module.to_list(self.module.use),
self.env, output_filename)
-class ns3pcfile_taskgen(TaskGen.task_gen):
- def __init__(self, *args, **kwargs):
- super(ns3pcfile_taskgen, self).__init__(*args, **kwargs)
- def apply(self):
- output_filename = 'lib%s.pc' % self.module.name
- output_node = self.path.find_or_declare(output_filename)
- assert output_node is not None, str(self)
- task = self.create_task('ns3pcfile', env=self.env)
- self.bld.install_files('${LIBDIR}/pkgconfig', output_node)
- task.set_outputs([output_node])
- task.module = self.module
+
+@TaskGen.feature('ns3pcfile')
+@TaskGen.after_method('process_rule')
+def apply(self):
+ output_filename = 'lib%s.pc' % self.module.name
+ output_node = self.path.find_or_declare(output_filename)
+ assert output_node is not None, str(self)
+ task = self.create_task('ns3pcfile')
+ self.bld.install_files('${LIBDIR}/pkgconfig', output_node)
+ task.set_outputs([output_node])
+ task.module = self.module
+
-class ns3header_taskgen(TaskGen.task_gen):
- """A set of NS-3 header files"""
- COLOR = 'BLUE'
- def __init__(self, *args, **kwargs):
- super(ns3header_taskgen, self).__init__(*args, **kwargs)
- self.install_path = None
- self.sub_dir = None # if not None, header files will be published as ns3/sub_dir/file.h
- self.module = None # module name
- self.mode = 'install'
+@TaskGen.feature('ns3header')
+@TaskGen.after_method('process_rule')
+def apply_ns3header(self):
+ if self.module is None:
+ raise WafError("'module' missing on ns3headers object %s" % self)
+ ns3_dir_node = self.bld.path.find_dir("ns3")
+ for filename in set(self.to_list(self.source)):
+ src_node = self.path.find_resource(filename)
+ if src_node is None:
+ raise WafError("source ns3 header file %s not found" % (filename,))
+ dst_node = ns3_dir_node.find_or_declare(src_node.name)
+ assert dst_node is not None
+ task = self.create_task('ns3header')
+ task.mode = getattr(self, 'mode', 'install')
+ if task.mode == 'install':
+ self.bld.install_files('${PREFIX}/include/ns3', [src_node])
+ task.set_inputs([src_node])
+ task.set_outputs([dst_node])
+ else:
+ task.header_to_remove = dst_node
+ self.headers = set(self.to_list(self.source))
+ self.source = '' # tell WAF not to process these files further
- def apply(self):
- for filename in set(self.to_list(self.source)):
- src_node = self.path.find_resource(filename)
- if self.module is None:
- raise Utils.WafError("'module' missing on ns3headers object %s" % self)
- ns3_dir_node = self.bld.path.find_dir("ns3")
- if self.sub_dir is not None:
- ns3_dir_node = ns3_dir_node.find_dir(self.sub_dir)
- for filename in set(self.to_list(self.source)):
- src_node = self.path.find_resource(filename)
- if src_node is None:
- raise Utils.WafError("source ns3 header file %s not found" % (filename,))
- dst_node = ns3_dir_node.find_or_declare(os.path.basename(filename))
- assert dst_node is not None
- task = self.create_task('ns3header', env=self.env)
- task.mode = self.mode
- if self.mode == 'install':
- self.bld.install_files('${PREFIX}/include/ns3', [src_node])
- task.set_inputs([src_node])
- task.set_outputs([dst_node])
- else:
- task.header_to_remove = dst_node
class ns3header_task(Task.Task):
- before = 'cc cxx gen_ns3_module_header_task'
+ before = 'cc cxx gen_ns3_module_header'
color = 'BLUE'
def __str__(self):
@@ -571,23 +449,41 @@
if self.outputs: sep = ' -> '
else: sep = ''
if self.mode == 'remove':
- return 'rm-ns3-header %s\n' % (self.header_to_remove.bldpath(self.env),)
+ return 'rm-ns3-header %s\n' % (self.header_to_remove.abspath(),)
return 'install-ns3-header: %s%s%s\n' % (src_str, sep, tgt_str)
+ def __repr__(self):
+ return str(self)
+
+ def uid(self):
+ try:
+ return self.uid_
+ except AttributeError:
+ m = Utils.md5()
+ up = m.update
+ up(self.__class__.__name__.encode())
+ for x in self.inputs + self.outputs:
+ up(x.abspath().encode())
+ up(self.mode)
+ if self.mode == 'remove':
+ up(self.header_to_remove.abspath().encode())
+ self.uid_ = m.digest()
+ return self.uid_
+
def runnable_status(self):
if self.mode == 'remove':
- if os.path.exists(self.header_to_remove.bldpath(self.env)):
- return Constants.RUN_ME
+ if os.path.exists(self.header_to_remove.abspath()):
+ return Task.RUN_ME
else:
- return Constants.SKIP_ME
+ return Task.SKIP_ME
else:
return super(ns3header_task, self).runnable_status()
def run(self):
if self.mode == 'install':
assert len(self.inputs) == len(self.outputs)
- inputs = [node.srcpath(self.env) for node in self.inputs]
- outputs = [node.bldpath(self.env) for node in self.outputs]
+ inputs = [node.abspath() for node in self.inputs]
+ outputs = [node.abspath() for node in self.outputs]
for src, dst in zip(inputs, outputs):
try:
os.chmod(dst, 0600)
@@ -601,7 +497,7 @@
else:
assert len(self.inputs) == 0
assert len(self.outputs) == 0
- out_file_name = self.header_to_remove.bldpath(self.env)
+ out_file_name = self.header_to_remove.abspath()
try:
os.unlink(out_file_name)
except OSError, ex:
@@ -612,15 +508,15 @@
class gen_ns3_module_header_task(Task.Task):
before = 'cc cxx'
- after = 'ns3header_task'
+ after = 'ns3header'
color = 'BLUE'
def runnable_status(self):
if self.mode == 'remove':
- if os.path.exists(self.header_to_remove.bldpath(self.env)):
- return Constants.RUN_ME
+ if os.path.exists(self.header_to_remove.abspath()):
+ return Task.RUN_ME
else:
- return Constants.SKIP_ME
+ return Task.SKIP_ME
else:
return super(gen_ns3_module_header_task, self).runnable_status()
@@ -632,24 +528,23 @@
if self.outputs: sep = ' -> '
else: sep = ''
if self.mode == 'remove':
- return 'rm-module-header %s\n' % (self.header_to_remove.bldpath(self.env),)
+ return 'rm-module-header %s\n' % (self.header_to_remove.abspath(),)
return 'gen-module-header: %s%s%s\n' % (src_str, sep, tgt_str)
def run(self):
if self.mode == 'remove':
assert len(self.inputs) == 0
assert len(self.outputs) == 0
- out_file_name = self.header_to_remove.bldpath(self.env)
+ out_file_name = self.header_to_remove.abspath()
try:
os.unlink(out_file_name)
except OSError, ex:
if ex.errno != 2:
raise
return 0
-
assert len(self.outputs) == 1
- out_file_name = self.outputs[0].bldpath(self.env)
- header_files = [os.path.basename(node.abspath(self.env)) for node in self.inputs]
+ out_file_name = self.outputs[0].get_bld().abspath()#self.env)
+ header_files = [os.path.basename(node.abspath()) for node in self.inputs]
outfile = file(out_file_name, "w")
header_files.sort()
@@ -677,7 +572,7 @@
return 0
def sig_explicit_deps(self):
- self.m.update('\n'.join([node.abspath(self.env) for node in self.inputs]))
+ self.m.update('\n'.join([node.abspath() for node in self.inputs]))
return self.m.digest()
def unique_id(self):
@@ -691,50 +586,46 @@
return self.uid
-class ns3moduleheader_taskgen(TaskGen.task_gen):
- """
- Generates a 'ns3/foo-module.h' header file that includes all
- public ns3 headers of a certain module.
- """
- COLOR = 'BLUE'
- def __init__(self, *args, **kwargs):
- super(ns3moduleheader_taskgen, self).__init__(*args, **kwargs)
- self.mode = 'install'
+# Generates a 'ns3/foo-module.h' header file that includes all public
+# ns3 headers of a certain module.
+@TaskGen.feature('ns3moduleheader')
+@TaskGen.after_method('process_rule')
+def apply_ns3moduleheader(self):
+ ## get all of the ns3 headers
+ ns3_dir_node = self.bld.path.find_dir("ns3")
+ all_headers_inputs = []
+ found_the_module = False
+ for ns3headers in self.bld.all_task_gen:
+ if 'ns3header' in getattr(ns3headers, "features", []):
+ if ns3headers.module != self.module:
+ continue
+ found_the_module = True
+ for source in ns3headers.headers:
+ source = os.path.basename(source)
+ node = ns3_dir_node.find_or_declare(os.path.basename(source))
+ if node is None:
+ fatal("missing header file %s" % (source,))
+ all_headers_inputs.append(node)
+ if not found_the_module:
+ raise WafError("error finding headers for module %s" % self.module)
+ if not all_headers_inputs:
+ return
- def apply(self):
- ## get all of the ns3 headers
- ns3_dir_node = self.bld.path.find_dir("ns3")
- all_headers_inputs = []
- found_the_module = False
- for ns3headers in self.bld.all_task_gen:
- if isinstance(ns3headers, ns3header_taskgen):
- if ns3headers.module != self.module:
- continue
- found_the_module = True
- for source in set(ns3headers.to_list(ns3headers.source)):
- source = os.path.basename(source)
- node = ns3_dir_node.find_or_declare(os.path.basename(source))
- if node is None:
- fatal("missing header file %s" % (source,))
- all_headers_inputs.append(node)
- if not found_the_module:
- raise Utils.WscriptError("error finding headers for module %s" % self.module)
- if not all_headers_inputs:
- return
- all_headers_outputs = [ns3_dir_node.find_or_declare("%s-module.h" % self.module)]
- task = self.create_task('gen_ns3_module_header', env=self.env)
- task.module = self.module
- task.mode = self.mode
- if self.mode == 'install':
- self.bld.install_files('${PREFIX}/include/ns3',
- ns3_dir_node.find_or_declare("%s-module.h" % self.module))
- task.set_inputs(all_headers_inputs)
- task.set_outputs(all_headers_outputs)
- module_obj = self.bld.name_to_obj("ns3-" + self.module, self.env)
- assert module_obj is not None, self.module
- task.module_deps = module_obj.module_deps
- else:
- task.header_to_remove = all_headers_outputs[0]
+ try:
+ module_obj = self.bld.get_tgen_by_name("ns3-" + self.module)
+ except WafError: # maybe the module was disabled, and therefore removed
+ return
- def install(self):
- pass
+ all_headers_outputs = [ns3_dir_node.find_or_declare("%s-module.h" % self.module)]
+ task = self.create_task('gen_ns3_module_header')
+ task.module = self.module
+ task.mode = getattr(self, "mode", "install")
+ if task.mode == 'install':
+ assert module_obj is not None, self.module
+ self.bld.install_files('${PREFIX}/include/ns3',
+ ns3_dir_node.find_or_declare("%s-module.h" % self.module))
+ task.set_inputs(all_headers_inputs)
+ task.set_outputs(all_headers_outputs)
+ task.module_deps = module_obj.module_deps
+ else:
+ task.header_to_remove = all_headers_outputs[0]
--- a/test.py Sat Aug 20 14:41:19 2011 -0400
+++ b/test.py Mon Oct 17 16:59:17 2011 -0400
@@ -42,7 +42,6 @@
# found in the associated subdirectory wscript files.
#
interesting_config_items = [
- "NS3_BUILDDIR",
"NS3_ENABLED_MODULES",
"NS3_MODULE_PATH",
"NSC_ENABLED",
@@ -483,24 +482,6 @@
thread_exit = True
return 0
-#
-# Waf can be configured to compile in debug or optimized modes. In each
-# case, the resulting built goes into a different directory. If we want
-# test tests to run from the correct code-base, we have to figure out which
-# mode waf is running in. This is called its active variant.
-#
-# XXX This function pokes around in the waf internal state file. To be a
-# little less hacky, we should add a commmand to waf to return this info
-# and use that result.
-#
-def read_waf_active_variant():
- for line in open("build/c4che/default.cache.py").readlines():
- if line.startswith("NS3_ACTIVE_VARIANT"):
- exec(line, globals())
- break
-
- if options.verbose:
- print "NS3_ACTIVE_VARIANT == %s" % NS3_ACTIVE_VARIANT
#
# In general, the build process itself naturally takes care of figuring out
@@ -519,7 +500,13 @@
# and use that result.
#
def read_waf_config():
- for line in open("build/c4che/%s.cache.py" % NS3_ACTIVE_VARIANT).readlines():
+ for line in open(".lock-wafbuild", "rt"):
+ if line.startswith("out_dir ="):
+ key, val = line.split('=')
+ out_dir = eval(val.strip())
+ global NS3_BUILDDIR
+ NS3_BUILDDIR = out_dir
+ for line in open("%s/c4che/_cache.py" % out_dir).readlines():
for item in interesting_config_items:
if line.startswith(item):
exec(line, globals())
@@ -555,7 +542,7 @@
if key == "PYTHONPATH":
have_PYTHONPATH = True
- pypath = os.environ["PYTHONPATH"] = os.path.join (NS3_BUILDDIR, NS3_ACTIVE_VARIANT, "bindings", "python")
+ pypath = os.environ["PYTHONPATH"] = os.path.join (NS3_BUILDDIR, "bindings", "python")
if not have_PYTHONPATH:
os.environ["PYTHONPATH"] = pypath
@@ -684,7 +671,7 @@
if len(build_path):
path_cmd = os.path.join (build_path, shell_command)
else:
- path_cmd = os.path.join (NS3_BUILDDIR, NS3_ACTIVE_VARIANT, shell_command)
+ path_cmd = os.path.join (NS3_BUILDDIR, shell_command)
if valgrind:
cmd = "valgrind --suppressions=%s --leak-check=full --show-reachable=yes --error-exitcode=2 %s" % (suppressions_path,
@@ -991,12 +978,11 @@
# pieces of the system have been built. This will tell us what examples
# are runnable.
#
- read_waf_active_variant()
read_waf_config()
make_paths()
# Get the information from the build status file.
- build_status_file = os.path.join (NS3_BUILDDIR, NS3_ACTIVE_VARIANT, 'build-status.py')
+ build_status_file = os.path.join (NS3_BUILDDIR, 'build-status.py')
if os.path.exists(build_status_file):
ns3_runnable_programs = get_list_from_file(build_status_file, "ns3_runnable_programs")
ns3_runnable_scripts = get_list_from_file(build_status_file, "ns3_runnable_scripts")
@@ -1013,7 +999,7 @@
# Set the directories and paths for this example.
example_directory = os.path.join("examples", directory)
examples_to_run_path = os.path.join(example_directory, "examples-to-run.py")
- cpp_executable_dir = os.path.join(NS3_BUILDDIR, NS3_ACTIVE_VARIANT, example_directory)
+ cpp_executable_dir = os.path.join(NS3_BUILDDIR, example_directory)
python_script_dir = os.path.join(example_directory)
# Parse this example directory's file.
@@ -1032,7 +1018,7 @@
module_directory = os.path.join("src", module)
example_directory = os.path.join(module_directory, "examples")
examples_to_run_path = os.path.join(module_directory, "test", "examples-to-run.py")
- cpp_executable_dir = os.path.join(NS3_BUILDDIR, NS3_ACTIVE_VARIANT, example_directory)
+ cpp_executable_dir = os.path.join(NS3_BUILDDIR, example_directory)
python_script_dir = os.path.join(example_directory)
# Parse this module's file.
--- a/utils/lcov/genhtml Sat Aug 20 14:41:19 2011 -0400
+++ b/utils/lcov/genhtml Mon Oct 17 16:59:17 2011 -0400
@@ -1,6 +1,6 @@
#!/usr/bin/perl -w
#
-# Copyright (c) International Business Machines Corp., 2002
+# Copyright (c) International Business Machines Corp., 2002,2010
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -48,6 +48,20 @@
# 2003-04-30 / Peter Oberparleiter: made info write to STDERR, not STDOUT
# 2003-07-10 / Peter Oberparleiter: added line checksum support
# 2004-08-09 / Peter Oberparleiter: added configuration file support
+# 2005-03-04 / Cal Pierog: added legend to HTML output, fixed coloring of
+# "good coverage" background
+# 2006-03-18 / Marcus Boerger: added --custom-intro, --custom-outro and
+# overwrite --no-prefix if --prefix is present
+# 2006-03-20 / Peter Oberparleiter: changes to custom_* function (rename
+# to html_prolog/_epilog, minor modifications to implementation),
+# changed prefix/noprefix handling to be consistent with current
+# logic
+# 2006-03-20 / Peter Oberparleiter: added --html-extension option
+# 2008-07-14 / Tom Zoerner: added --function-coverage command line option;
+# added function table to source file page
+# 2008-08-13 / Peter Oberparleiter: modified function coverage
+# implementation (now enabled per default),
+# introduced sorting option (enabled per default)
#
use strict;
@@ -57,16 +71,27 @@
# Global constants
-our $title = "LTP GCOV extension - code coverage report";
-our $lcov_version = "LTP GCOV extension version 1.4";
+our $title = "LCOV - code coverage report";
+our $lcov_version = 'LCOV version 1.9';
our $lcov_url = "http://ltp.sourceforge.net/coverage/lcov.php";
+our $tool_name = basename($0);
# Specify coverage rate limits (in %) for classifying file entries
# HI: $hi_limit <= rate <= 100 graph color: green
# MED: $med_limit <= rate < $hi_limit graph color: orange
# LO: 0 <= rate < $med_limit graph color: red
-our $hi_limit = 50;
-our $med_limit = 15;
+
+# For line coverage/all coverage types if not specified
+our $hi_limit = 90;
+our $med_limit = 75;
+
+# For function coverage
+our $fn_hi_limit;
+our $fn_med_limit;
+
+# For branch coverage
+our $br_hi_limit;
+our $br_med_limit;
# Width of overview image
our $overview_width = 80;
@@ -81,31 +106,78 @@
# line in the window. This number specifies that offset in lines.
our $nav_offset = 10;
-our $overview_title = "directory";
+# Clicking on a function name should show the source code at a position a
+# few lines before the first line of code of that function. This number
+# specifies that offset in lines.
+our $func_offset = 2;
+
+our $overview_title = "top level";
+
+# Width for line coverage information in the source code view
+our $line_field_width = 12;
+
+# Width for branch coverage information in the source code view
+our $br_field_width = 16;
+
+# Internal Constants
+
+# Header types
+our $HDR_DIR = 0;
+our $HDR_FILE = 1;
+our $HDR_SOURCE = 2;
+our $HDR_TESTDESC = 3;
+our $HDR_FUNC = 4;
+
+# Sort types
+our $SORT_FILE = 0;
+our $SORT_LINE = 1;
+our $SORT_FUNC = 2;
+our $SORT_BRANCH = 3;
+
+# Fileview heading types
+our $HEAD_NO_DETAIL = 1;
+our $HEAD_DETAIL_HIDDEN = 2;
+our $HEAD_DETAIL_SHOWN = 3;
+
+# Offsets for storing branch coverage data in vectors
+our $BR_BLOCK = 0;
+our $BR_BRANCH = 1;
+our $BR_TAKEN = 2;
+our $BR_VEC_ENTRIES = 3;
+our $BR_VEC_WIDTH = 32;
+
+# Additional offsets used when converting branch coverage data to HTML
+our $BR_LEN = 3;
+our $BR_OPEN = 4;
+our $BR_CLOSE = 5;
+
+# Branch data combination types
+our $BR_SUB = 0;
+our $BR_ADD = 1;
# Data related prototypes
sub print_usage(*);
sub gen_html();
+sub html_create($$);
sub process_dir($);
sub process_file($$$);
sub info(@);
sub read_info_file($);
sub get_info_entry($);
-sub set_info_entry($$$$$;$$);
+sub set_info_entry($$$$$$$$$;$$$$$$);
sub get_prefix(@);
sub shorten_prefix($);
sub get_dir_list(@);
sub get_relative_base_path($);
sub read_testfile($);
sub get_date_string();
-sub split_filename($);
sub create_sub_dir($);
sub subtract_counts($$);
sub add_counts($$);
sub apply_baseline($$);
sub remove_unused_descriptions();
sub get_found_and_hit($);
-sub get_affecting_tests($);
+sub get_affecting_tests($$$);
sub combine_info_files($$);
sub merge_checksums($$$);
sub combine_info_entries($$$);
@@ -113,6 +185,19 @@
sub system_no_output($@);
sub read_config($);
sub apply_config($);
+sub get_html_prolog($);
+sub get_html_epilog($);
+sub write_dir_page($$$$$$$$$$$$$$$$$);
+sub classify_rate($$$$);
+sub br_taken_add($$);
+sub br_taken_sub($$);
+sub br_ivec_len($);
+sub br_ivec_get($$);
+sub br_ivec_push($$$$);
+sub combine_brcount($$$);
+sub get_br_found_and_hit($);
+sub warn_handler($);
+sub die_handler($);
# HTML related prototypes
@@ -120,32 +205,33 @@
sub get_bar_graph_code($$$);
sub write_png_files();
+sub write_htaccess_file();
sub write_css_file();
-sub write_description_file($$$);
+sub write_description_file($$$$$$$);
+sub write_function_table(*$$$$$$$$$$);
sub write_html(*$);
sub write_html_prolog(*$$);
sub write_html_epilog(*$;$);
-sub write_header(*$$$$$);
+sub write_header(*$$$$$$$$$$);
sub write_header_prolog(*$);
-sub write_header_line(*$$;$$);
+sub write_header_line(*@);
sub write_header_epilog(*$);
-sub write_file_table(*$$$$);
-sub write_file_table_prolog(*$$);
-sub write_file_table_entry(*$$$$);
-sub write_file_table_detail_heading(*$$);
-sub write_file_table_detail_entry(*$$$);
+sub write_file_table(*$$$$$$$);
+sub write_file_table_prolog(*$@);
+sub write_file_table_entry(*$$$@);
+sub write_file_table_detail_entry(*$@);
sub write_file_table_epilog(*);
sub write_test_table_prolog(*$);
sub write_test_table_entry(*$$);
sub write_test_table_epilog(*);
-sub write_source($$$$$);
+sub write_source($$$$$$$);
sub write_source_prolog(*);
-sub write_source_line(*$$$$);
+sub write_source_line(*$$$$$$);
sub write_source_epilog(*);
sub write_frameset(*$$$);
@@ -173,12 +259,31 @@
our $version; # Version option flag
our $show_details; # If set, generate detailed directory view
our $no_prefix; # If set, do not remove filename prefix
+our $func_coverage = 1; # If set, generate function coverage statistics
+our $no_func_coverage; # Disable func_coverage
+our $br_coverage = 1; # If set, generate branch coverage statistics
+our $no_br_coverage; # Disable br_coverage
+our $sort = 1; # If set, provide directory listings with sorted entries
+our $no_sort; # Disable sort
our $frames; # If set, use frames for source code view
our $keep_descriptions; # If set, do not remove unused test case descriptions
our $no_sourceview; # If set, do not create a source code view for each file
our $highlight; # If set, highlight lines covered by converted data only
+our $legend; # If set, include legend in output
our $tab_size = 8; # Number of spaces to use in place of tab
our $config; # Configuration file contents
+our $html_prolog_file; # Custom HTML prolog file (up to and including <body>)
+our $html_epilog_file; # Custom HTML epilog file (from </body> onwards)
+our $html_prolog; # Actual HTML prolog
+our $html_epilog; # Actual HTML epilog
+our $html_ext = "html"; # Extension for generated HTML files
+our $html_gzip = 0; # Compress with gzip
+our $demangle_cpp = 0; # Demangle C++ function names
+our @fileview_sortlist;
+our @fileview_sortname = ("", "-sort-l", "-sort-f", "-sort-b");
+our @funcview_sortlist;
+our @rate_name = ("Lo", "Med", "Hi");
+our @rate_png = ("ruby.png", "amber.png", "emerald.png");
our $cwd = `pwd`; # Current working directory
chomp($cwd);
@@ -189,6 +294,12 @@
# Code entry point
#
+$SIG{__WARN__} = \&warn_handler;
+$SIG{__DIE__} = \&die_handler;
+
+# Prettify version string
+$lcov_version =~ s/\$\s*Revision\s*:?\s*(\S+)\s*\$/$1/;
+
# Add current working directory if $tool_dir is not already an absolute path
if (! ($tool_dir =~ /^\/(.*)$/))
{
@@ -196,7 +307,7 @@
}
# Read configuration file if available
-if (-r $ENV{"HOME"}."/.lcovrc")
+if (defined($ENV{"HOME"}) && (-r $ENV{"HOME"}."/.lcovrc"))
{
$config = read_config($ENV{"HOME"}."/.lcovrc");
}
@@ -212,6 +323,7 @@
"genhtml_css_file" => \$css_filename,
"genhtml_hi_limit" => \$hi_limit,
"genhtml_med_limit" => \$med_limit,
+ "genhtml_line_field_width" => \$line_field_width,
"genhtml_overview_width" => \$overview_width,
"genhtml_nav_resolution" => \$nav_resolution,
"genhtml_nav_offset" => \$nav_offset,
@@ -219,30 +331,75 @@
"genhtml_no_prefix" => \$no_prefix,
"genhtml_no_source" => \$no_sourceview,
"genhtml_num_spaces" => \$tab_size,
- "genhtml_highlight" => \$highlight});
+ "genhtml_highlight" => \$highlight,
+ "genhtml_legend" => \$legend,
+ "genhtml_html_prolog" => \$html_prolog_file,
+ "genhtml_html_epilog" => \$html_epilog_file,
+ "genhtml_html_extension" => \$html_ext,
+ "genhtml_html_gzip" => \$html_gzip,
+ "genhtml_function_hi_limit" => \$fn_hi_limit,
+ "genhtml_function_med_limit" => \$fn_med_limit,
+ "genhtml_function_coverage" => \$func_coverage,
+ "genhtml_branch_hi_limit" => \$br_hi_limit,
+ "genhtml_branch_med_limit" => \$br_med_limit,
+ "genhtml_branch_coverage" => \$br_coverage,
+ "genhtml_branch_field_width" => \$br_field_width,
+ "genhtml_sort" => \$sort,
+ });
}
+# Copy limit values if not specified
+$fn_hi_limit = $hi_limit if (!defined($fn_hi_limit));
+$fn_med_limit = $med_limit if (!defined($fn_med_limit));
+$br_hi_limit = $hi_limit if (!defined($br_hi_limit));
+$br_med_limit = $med_limit if (!defined($br_med_limit));
+
# Parse command line options
-if (!GetOptions("output-directory=s" => \$output_directory,
- "title=s" => \$test_title,
- "description-file=s" => \$desc_filename,
- "keep-descriptions" => \$keep_descriptions,
- "css-file=s" => \$css_filename,
- "baseline-file=s" => \$base_filename,
- "prefix=s" => \$dir_prefix,
+if (!GetOptions("output-directory|o=s" => \$output_directory,
+ "title|t=s" => \$test_title,
+ "description-file|d=s" => \$desc_filename,
+ "keep-descriptions|k" => \$keep_descriptions,
+ "css-file|c=s" => \$css_filename,
+ "baseline-file|b=s" => \$base_filename,
+ "prefix|p=s" => \$dir_prefix,
"num-spaces=i" => \$tab_size,
"no-prefix" => \$no_prefix,
"no-sourceview" => \$no_sourceview,
- "show-details" => \$show_details,
- "frames" => \$frames,
+ "show-details|s" => \$show_details,
+ "frames|f" => \$frames,
"highlight" => \$highlight,
- "quiet" => \$quiet,
- "help|h" => \$help,
- "version" => \$version
+ "legend" => \$legend,
+ "quiet|q" => \$quiet,
+ "help|h|?" => \$help,
+ "version|v" => \$version,
+ "html-prolog=s" => \$html_prolog_file,
+ "html-epilog=s" => \$html_epilog_file,
+ "html-extension=s" => \$html_ext,
+ "html-gzip" => \$html_gzip,
+ "function-coverage" => \$func_coverage,
+ "no-function-coverage" => \$no_func_coverage,
+ "branch-coverage" => \$br_coverage,
+ "no-branch-coverage" => \$no_br_coverage,
+ "sort" => \$sort,
+ "no-sort" => \$no_sort,
+ "demangle-cpp" => \$demangle_cpp,
))
{
- print_usage(*STDERR);
+ print(STDERR "Use $tool_name --help to get usage information\n");
exit(1);
+} else {
+ # Merge options
+ if ($no_func_coverage) {
+ $func_coverage = 0;
+ }
+ if ($no_br_coverage) {
+ $br_coverage = 0;
+ }
+
+ # Merge sort options
+ if ($no_sort) {
+ $sort = 0;
+ }
}
@info_filenames = @ARGV;
@@ -257,16 +414,15 @@
# Check for version option
if ($version)
{
- print($lcov_version."\n");
+ print("$tool_name: $lcov_version\n");
exit(0);
}
# Check for info filename
if (!@info_filenames)
{
- print(STDERR "No filename specified\n");
- print_usage(*STDERR);
- exit(1);
+ die("No filename specified\n".
+ "Use $tool_name --help to get usage information\n");
}
# Generate a title if none is specified
@@ -302,20 +458,51 @@
exit(1);
}
+# Get HTML prolog and epilog
+$html_prolog = get_html_prolog($html_prolog_file);
+$html_epilog = get_html_epilog($html_epilog_file);
+
# Issue a warning if --no-sourceview is enabled together with --frames
-if ($no_sourceview && $frames)
+if ($no_sourceview && defined($frames))
{
warn("WARNING: option --frames disabled because --no-sourceview ".
"was specified!\n");
$frames = undef;
}
+# Issue a warning if --no-prefix is enabled together with --prefix
+if ($no_prefix && defined($dir_prefix))
+{
+ warn("WARNING: option --prefix disabled because --no-prefix was ".
+ "specified!\n");
+ $dir_prefix = undef;
+}
+
+@fileview_sortlist = ($SORT_FILE);
+@funcview_sortlist = ($SORT_FILE);
+
+if ($sort) {
+ push(@fileview_sortlist, $SORT_LINE);
+ push(@fileview_sortlist, $SORT_FUNC) if ($func_coverage);
+ push(@fileview_sortlist, $SORT_BRANCH) if ($br_coverage);
+ push(@funcview_sortlist, $SORT_LINE);
+}
+
if ($frames)
{
# Include genpng code needed for overview image generation
do("$tool_dir/genpng");
}
+# Ensure that the c++filt tool is available when using --demangle-cpp
+if ($demangle_cpp)
+{
+ if (system_no_output(3, "c++filt", "--version")) {
+ die("ERROR: could not find c++filt tool needed for ".
+ "--demangle-cpp\n");
+ }
+}
+
# Make sure output_directory exists, create it if necessary
if ($output_directory)
{
@@ -323,12 +510,10 @@
if (! -e _)
{
- system("mkdir", "-p", $output_directory)
- and die("ERROR: cannot create directory $_!\n");
+ create_sub_dir($output_directory);
}
}
-
# Do something
gen_html();
@@ -345,38 +530,114 @@
sub print_usage(*)
{
local *HANDLE = $_[0];
- my $executable_name = basename($0);
print(HANDLE <<END_OF_USAGE);
-Usage: $executable_name [OPTIONS] INFOFILE(S)
+Usage: $tool_name [OPTIONS] INFOFILE(S)
Create HTML output for coverage data found in INFOFILE. Note that INFOFILE
may also be a list of filenames.
+Misc:
-h, --help Print this help, then exit
-v, --version Print version number, then exit
-q, --quiet Do not print progress messages
+
+Operation:
+ -o, --output-directory OUTDIR Write HTML output to OUTDIR
-s, --show-details Generate detailed directory view
- -f, --frames Use HTML frames for source code view
- -b, --baseline-file BASEFILE Use BASEFILE as baseline file
- -o, --output-directory OUTDIR Write HTML output to OUTDIR
- -t, --title TITLE Display TITLE in header of all pages
-d, --description-file DESCFILE Read test case descriptions from DESCFILE
-k, --keep-descriptions Do not remove unused test descriptions
- -c, --css-file CSSFILE Use external style sheet file CSSFILE
+ -b, --baseline-file BASEFILE Use BASEFILE as baseline file
-p, --prefix PREFIX Remove PREFIX from all directory names
--no-prefix Do not remove prefix from directory names
+ --(no-)function-coverage Enable (disable) function coverage display
+ --(no-)branch-coverage Enable (disable) branch coverage display
+
+HTML output:
+ -f, --frames Use HTML frames for source code view
+ -t, --title TITLE Display TITLE in header of all pages
+ -c, --css-file CSSFILE Use external style sheet file CSSFILE
--no-source Do not create source code view
--num-spaces NUM Replace tabs with NUM spaces in source view
--highlight Highlight lines with converted-only data
-
-See $lcov_url for more information about this tool.
+ --legend Include color legend in HTML output
+ --html-prolog FILE Use FILE as HTML prolog for generated pages
+ --html-epilog FILE Use FILE as HTML epilog for generated pages
+ --html-extension EXT Use EXT as filename extension for pages
+ --html-gzip Use gzip to compress HTML
+ --(no-)sort Enable (disable) sorted coverage views
+ --demangle-cpp Demangle C++ function names
+
+For more information see: $lcov_url
END_OF_USAGE
;
}
#
+# get_rate(found, hit)
+#
+# Return a relative value for the specified found&hit values
+# which is used for sorting the corresponding entries in a
+# file list.
+#
+
+sub get_rate($$)
+{
+ my ($found, $hit) = @_;
+
+ if ($found == 0) {
+ return 10000;
+ }
+ return int($hit * 1000 / $found) * 10 + 2 - (1 / $found);
+}
+
+
+#
+# get_overall_line(found, hit, name_singular, name_plural)
+#
+# Return a string containing overall information for the specified
+# found/hit data.
+#
+
+sub get_overall_line($$$$)
+{
+ my ($found, $hit, $name_sn, $name_pl) = @_;
+ my $name;
+
+ return "no data found" if (!defined($found) || $found == 0);
+ $name = ($found == 1) ? $name_sn : $name_pl;
+ return sprintf("%.1f%% (%d of %d %s)", $hit * 100 / $found, $hit,
+ $found, $name);
+}
+
+
+#
+# print_overall_rate(ln_do, ln_found, ln_hit, fn_do, fn_found, fn_hit, br_do
+# br_found, br_hit)
+#
+# Print overall coverage rates for the specified coverage types.
+#
+
+sub print_overall_rate($$$$$$$$$)
+{
+ my ($ln_do, $ln_found, $ln_hit, $fn_do, $fn_found, $fn_hit,
+ $br_do, $br_found, $br_hit) = @_;
+
+ info("Overall coverage rate:\n");
+ info(" lines......: %s\n",
+ get_overall_line($ln_found, $ln_hit, "line", "lines"))
+ if ($ln_do);
+ info(" functions..: %s\n",
+ get_overall_line($fn_found, $fn_hit, "function", "functions"))
+ if ($fn_do);
+ info(" branches...: %s\n",
+ get_overall_line($br_found, $br_hit, "branch", "branches"))
+ if ($br_do);
+}
+
+
+#
# gen_html()
#
# Generate a set of HTML pages from contents of .info file INFO_FILENAME.
@@ -394,8 +655,16 @@
my %base_data;
my $lines_found;
my $lines_hit;
+ my $fn_found;
+ my $fn_hit;
+ my $br_found;
+ my $br_hit;
my $overall_found = 0;
my $overall_hit = 0;
+ my $total_fn_found = 0;
+ my $total_fn_hit = 0;
+ my $total_br_found = 0;
+ my $total_br_hit = 0;
my $dir_name;
my $link_name;
my @dir_list;
@@ -404,7 +673,6 @@
# Read in all specified .info files
foreach (@info_filenames)
{
- info("Reading data file $_\n");
%new_info = %{read_info_file($_)};
# Combine %new_info with %info_data
@@ -480,12 +748,20 @@
write_css_file();
write_png_files();
+ if ($html_gzip)
+ {
+ info("Writing .htaccess file.\n");
+ write_htaccess_file();
+ }
+
info("Generating output.\n");
# Process each subdirectory and collect overview information
foreach $dir_name (@dir_list)
{
- ($lines_found, $lines_hit) = process_dir($dir_name);
+ ($lines_found, $lines_hit, $fn_found, $fn_hit,
+ $br_found, $br_hit)
+ = process_dir($dir_name);
# Remove prefix if applicable
if (!$no_prefix && $dir_prefix)
@@ -497,48 +773,96 @@
# Generate name for directory overview HTML page
if ($dir_name =~ /^\/(.*)$/)
{
- $link_name = substr($dir_name, 1)."/index.html";
+ $link_name = substr($dir_name, 1)."/index.$html_ext";
}
else
{
- $link_name = $dir_name."/index.html";
+ $link_name = $dir_name."/index.$html_ext";
}
- $overview{$dir_name} = "$lines_found,$lines_hit,$link_name";
+ $overview{$dir_name} = [$lines_found, $lines_hit, $fn_found,
+ $fn_hit, $br_found, $br_hit, $link_name,
+ get_rate($lines_found, $lines_hit),
+ get_rate($fn_found, $fn_hit),
+ get_rate($br_found, $br_hit)];
$overall_found += $lines_found;
$overall_hit += $lines_hit;
+ $total_fn_found += $fn_found;
+ $total_fn_hit += $fn_hit;
+ $total_br_found += $br_found;
+ $total_br_hit += $br_hit;
}
# Generate overview page
info("Writing directory view page.\n");
- open(*HTML_HANDLE, ">index.html")
- or die("ERROR: cannot open index.html for writing!\n");
- write_html_prolog(*HTML_HANDLE, "", "LCOV - $test_title");
- write_header(*HTML_HANDLE, 0, "", "", $overall_found, $overall_hit);
- write_file_table(*HTML_HANDLE, "", \%overview, {}, 0);
- write_html_epilog(*HTML_HANDLE, "");
- close(*HTML_HANDLE);
+
+ # Create sorted pages
+ foreach (@fileview_sortlist) {
+ write_dir_page($fileview_sortname[$_], ".", "", $test_title,
+ undef, $overall_found, $overall_hit,
+ $total_fn_found, $total_fn_hit, $total_br_found,
+ $total_br_hit, \%overview, {}, {}, {}, 0, $_);
+ }
# Check if there are any test case descriptions to write out
if (%test_description)
{
info("Writing test case description file.\n");
write_description_file( \%test_description,
- $overall_found, $overall_hit);
- }
-
- if ($overall_found == 0)
+ $overall_found, $overall_hit,
+ $total_fn_found, $total_fn_hit,
+ $total_br_found, $total_br_hit);
+ }
+
+ print_overall_rate(1, $overall_found, $overall_hit,
+ $func_coverage, $total_fn_found, $total_fn_hit,
+ $br_coverage, $total_br_found, $total_br_hit);
+
+ chdir($cwd);
+}
+
+#
+# html_create(handle, filename)
+#
+
+sub html_create($$)
+{
+ my $handle = $_[0];
+ my $filename = $_[1];
+
+ if ($html_gzip)
{
- info("Warning: No lines found!\n");
+ open($handle, "|gzip -c >$filename")
+ or die("ERROR: cannot open $filename for writing ".
+ "(gzip)!\n");
}
else
{
- info("Overall coverage rate: %d of %d lines (%.1f%%)\n",
- $overall_hit, $overall_found,
- $overall_hit*100/$overall_found);
- }
-
- chdir($cwd);
+ open($handle, ">$filename")
+ or die("ERROR: cannot open $filename for writing!\n");
+ }
+}
+
+sub write_dir_page($$$$$$$$$$$$$$$$$)
+{
+ my ($name, $rel_dir, $base_dir, $title, $trunc_dir, $overall_found,
+ $overall_hit, $total_fn_found, $total_fn_hit, $total_br_found,
+ $total_br_hit, $overview, $testhash, $testfnchash, $testbrhash,
+ $view_type, $sort_type) = @_;
+
+ # Generate directory overview page including details
+ html_create(*HTML_HANDLE, "$rel_dir/index$name.$html_ext");
+ if (!defined($trunc_dir)) {
+ $trunc_dir = "";
+ }
+ write_html_prolog(*HTML_HANDLE, $base_dir, "LCOV - $title$trunc_dir");
+ write_header(*HTML_HANDLE, $view_type, $trunc_dir, $rel_dir,
+ $overall_found, $overall_hit, $total_fn_found,
+ $total_fn_hit, $total_br_found, $total_br_hit, $sort_type);
+ write_file_table(*HTML_HANDLE, $base_dir, $overview, $testhash,
+ $testfnchash, $testbrhash, $view_type, $sort_type);
+ write_html_epilog(*HTML_HANDLE, $base_dir);
+ close(*HTML_HANDLE);
}
@@ -556,12 +880,25 @@
my %overview;
my $lines_found;
my $lines_hit;
+ my $fn_found;
+ my $fn_hit;
+ my $br_found;
+ my $br_hit;
my $overall_found=0;
my $overall_hit=0;
+ my $total_fn_found=0;
+ my $total_fn_hit=0;
+ my $total_br_found = 0;
+ my $total_br_hit = 0;
my $base_name;
my $extension;
my $testdata;
my %testhash;
+ my $testfncdata;
+ my %testfnchash;
+ my $testbrdata;
+ my %testbrhash;
+ my @sort_list;
local *HTML_HANDLE;
# Remove prefix if applicable
@@ -587,70 +924,68 @@
# sub-directories
foreach $filename (grep(/^\Q$abs_dir\E\/[^\/]*$/,keys(%info_data)))
{
- ($lines_found, $lines_hit, $testdata) =
+ my $page_link;
+ my $func_link;
+
+ ($lines_found, $lines_hit, $fn_found, $fn_hit, $br_found,
+ $br_hit, $testdata, $testfncdata, $testbrdata) =
process_file($trunc_dir, $rel_dir, $filename);
$base_name = basename($filename);
- if ($no_sourceview)
- {
- # User asked as not to create source code view, do not
- # provide a page link
- $overview{$base_name} =
- "$lines_found,$lines_hit";
- }
- elsif ($frames)
- {
+ if ($no_sourceview) {
+ $page_link = "";
+ } elsif ($frames) {
# Link to frameset page
- $overview{$base_name} =
- "$lines_found,$lines_hit,".
- "$base_name.gcov.frameset.html";
+ $page_link = "$base_name.gcov.frameset.$html_ext";
+ } else {
+ # Link directory to source code view page
+ $page_link = "$base_name.gcov.$html_ext";
}
- else
- {
- # Link directory to source code view page
- $overview{$base_name} =
- "$lines_found,$lines_hit,".
- "$base_name.gcov.html";
- }
+ $overview{$base_name} = [$lines_found, $lines_hit, $fn_found,
+ $fn_hit, $br_found, $br_hit,
+ $page_link,
+ get_rate($lines_found, $lines_hit),
+ get_rate($fn_found, $fn_hit),
+ get_rate($br_found, $br_hit)];
$testhash{$base_name} = $testdata;
+ $testfnchash{$base_name} = $testfncdata;
+ $testbrhash{$base_name} = $testbrdata;
$overall_found += $lines_found;
$overall_hit += $lines_hit;
- }
-
- # Generate directory overview page (without details)
- open(*HTML_HANDLE, ">$rel_dir/index.html")
- or die("ERROR: cannot open $rel_dir/index.html ".
- "for writing!\n");
- write_html_prolog(*HTML_HANDLE, $base_dir,
- "LCOV - $test_title - $trunc_dir");
- write_header(*HTML_HANDLE, 1, $trunc_dir, $rel_dir, $overall_found,
- $overall_hit);
- write_file_table(*HTML_HANDLE, $base_dir, \%overview, {}, 1);
- write_html_epilog(*HTML_HANDLE, $base_dir);
- close(*HTML_HANDLE);
-
- if ($show_details)
- {
+
+ $total_fn_found += $fn_found;
+ $total_fn_hit += $fn_hit;
+
+ $total_br_found += $br_found;
+ $total_br_hit += $br_hit;
+ }
+
+ # Create sorted pages
+ foreach (@fileview_sortlist) {
+ # Generate directory overview page (without details)
+ write_dir_page($fileview_sortname[$_], $rel_dir, $base_dir,
+ $test_title, $trunc_dir, $overall_found,
+ $overall_hit, $total_fn_found, $total_fn_hit,
+ $total_br_found, $total_br_hit, \%overview, {},
+ {}, {}, 1, $_);
+ if (!$show_details) {
+ next;
+ }
# Generate directory overview page including details
- open(*HTML_HANDLE, ">$rel_dir/index-detail.html")
- or die("ERROR: cannot open $rel_dir/".
- "index-detail.html for writing!\n");
- write_html_prolog(*HTML_HANDLE, $base_dir,
- "LCOV - $test_title - $trunc_dir");
- write_header(*HTML_HANDLE, 1, $trunc_dir, $rel_dir,
- $overall_found,
- $overall_hit);
- write_file_table(*HTML_HANDLE, $base_dir, \%overview,
- \%testhash, 1);
- write_html_epilog(*HTML_HANDLE, $base_dir);
- close(*HTML_HANDLE);
+ write_dir_page("-detail".$fileview_sortname[$_], $rel_dir,
+ $base_dir, $test_title, $trunc_dir,
+ $overall_found, $overall_hit, $total_fn_found,
+ $total_fn_hit, $total_br_found, $total_br_hit,
+ \%overview, \%testhash, \%testfnchash,
+ \%testbrhash, 1, $_);
}
# Calculate resulting line counts
- return ($overall_found, $overall_hit);
+ return ($overall_found, $overall_hit, $total_fn_found, $total_fn_hit,
+ $total_br_found, $total_br_hit);
}
@@ -711,6 +1046,37 @@
}
+sub write_function_page($$$$$$$$$$$$$$$$$$)
+{
+ my ($base_dir, $rel_dir, $trunc_dir, $base_name, $title,
+ $lines_found, $lines_hit, $fn_found, $fn_hit, $br_found, $br_hit,
+ $sumcount, $funcdata, $sumfnccount, $testfncdata, $sumbrcount,
+ $testbrdata, $sort_type) = @_;
+ my $pagetitle;
+ my $filename;
+
+ # Generate function table for this file
+ if ($sort_type == 0) {
+ $filename = "$rel_dir/$base_name.func.$html_ext";
+ } else {
+ $filename = "$rel_dir/$base_name.func-sort-c.$html_ext";
+ }
+ html_create(*HTML_HANDLE, $filename);
+ $pagetitle = "LCOV - $title - $trunc_dir/$base_name - functions";
+ write_html_prolog(*HTML_HANDLE, $base_dir, $pagetitle);
+ write_header(*HTML_HANDLE, 4, "$trunc_dir/$base_name",
+ "$rel_dir/$base_name", $lines_found, $lines_hit,
+ $fn_found, $fn_hit, $br_found, $br_hit, $sort_type);
+ write_function_table(*HTML_HANDLE, "$base_name.gcov.$html_ext",
+ $sumcount, $funcdata,
+ $sumfnccount, $testfncdata, $sumbrcount,
+ $testbrdata, $base_name,
+ $base_dir, $sort_type);
+ write_html_epilog(*HTML_HANDLE, $base_dir, 1);
+ close(*HTML_HANDLE);
+}
+
+
#
# process_file(trunc_dir, rel_dir, filename)
#
@@ -729,42 +1095,69 @@
my $sumcount;
my $funcdata;
my $checkdata;
+ my $testfncdata;
+ my $sumfnccount;
+ my $testbrdata;
+ my $sumbrcount;
my $lines_found;
my $lines_hit;
+ my $fn_found;
+ my $fn_hit;
+ my $br_found;
+ my $br_hit;
my $converted;
my @source;
my $pagetitle;
local *HTML_HANDLE;
- ($testdata, $sumcount, $funcdata, $checkdata, $lines_found,
- $lines_hit) = get_info_entry($info_data{$filename});
+ ($testdata, $sumcount, $funcdata, $checkdata, $testfncdata,
+ $sumfnccount, $testbrdata, $sumbrcount, $lines_found, $lines_hit,
+ $fn_found, $fn_hit, $br_found, $br_hit)
+ = get_info_entry($info_data{$filename});
# Return after this point in case user asked us not to generate
# source code view
if ($no_sourceview)
{
- return ($lines_found, $lines_hit, $testdata);
+ return ($lines_found, $lines_hit, $fn_found, $fn_hit,
+ $br_found, $br_hit, $testdata, $testfncdata,
+ $testbrdata);
}
$converted = get_converted_lines($testdata);
# Generate source code view for this file
- open(*HTML_HANDLE, ">$rel_dir/$base_name.gcov.html")
- or die("ERROR: cannot open $rel_dir/$base_name.gcov.html ".
- "for writing!\n");
+ html_create(*HTML_HANDLE, "$rel_dir/$base_name.gcov.$html_ext");
$pagetitle = "LCOV - $test_title - $trunc_dir/$base_name";
write_html_prolog(*HTML_HANDLE, $base_dir, $pagetitle);
write_header(*HTML_HANDLE, 2, "$trunc_dir/$base_name",
- "$rel_dir/$base_name", $lines_found, $lines_hit);
+ "$rel_dir/$base_name", $lines_found, $lines_hit,
+ $fn_found, $fn_hit, $br_found, $br_hit, 0);
@source = write_source(*HTML_HANDLE, $filename, $sumcount, $checkdata,
- $converted);
+ $converted, $funcdata, $sumbrcount);
write_html_epilog(*HTML_HANDLE, $base_dir, 1);
close(*HTML_HANDLE);
+ if ($func_coverage) {
+ # Create function tables
+ foreach (@funcview_sortlist) {
+ write_function_page($base_dir, $rel_dir, $trunc_dir,
+ $base_name, $test_title,
+ $lines_found, $lines_hit,
+ $fn_found, $fn_hit, $br_found,
+ $br_hit, $sumcount,
+ $funcdata, $sumfnccount,
+ $testfncdata, $sumbrcount,
+ $testbrdata, $_);
+ }
+ }
+
# Additional files are needed in case of frame output
if (!$frames)
{
- return ($lines_found, $lines_hit, $testdata);
+ return ($lines_found, $lines_hit, $fn_found, $fn_hit,
+ $br_found, $br_hit, $testdata, $testfncdata,
+ $testbrdata);
}
# Create overview png file
@@ -772,23 +1165,20 @@
@source);
# Create frameset page
- open(*HTML_HANDLE, ">$rel_dir/$base_name.gcov.frameset.html")
- or die("ERROR: cannot open ".
- "$rel_dir/$base_name.gcov.frameset.html".
- " for writing!\n");
+ html_create(*HTML_HANDLE,
+ "$rel_dir/$base_name.gcov.frameset.$html_ext");
write_frameset(*HTML_HANDLE, $base_dir, $base_name, $pagetitle);
close(*HTML_HANDLE);
# Write overview frame
- open(*HTML_HANDLE, ">$rel_dir/$base_name.gcov.overview.html")
- or die("ERROR: cannot open ".
- "$rel_dir/$base_name.gcov.overview.html".
- " for writing!\n");
+ html_create(*HTML_HANDLE,
+ "$rel_dir/$base_name.gcov.overview.$html_ext");
write_overview(*HTML_HANDLE, $base_dir, $base_name, $pagetitle,
scalar(@source));
close(*HTML_HANDLE);
- return ($lines_found, $lines_hit, $testdata);
+ return ($lines_found, $lines_hit, $fn_found, $fn_hit, $br_found,
+ $br_hit, $testdata, $testfncdata, $testbrdata);
}
@@ -806,13 +1196,24 @@
# "found" -> $lines_found (number of instrumented lines found in file)
# "hit" -> $lines_hit (number of executed lines in file)
# "check" -> \%checkdata
-#
-# %testdata: name of test affecting this file -> \%testcount
-#
-# %testcount: line number -> execution count for a single test
-# %sumcount : line number -> execution count for all tests
-# %funcdata : line number -> name of function beginning at that line
-# %checkdata: line number -> checksum of source code line
+# "testfnc" -> \%testfncdata
+# "sumfnc" -> \%sumfnccount
+# "testbr" -> \%testbrdata
+# "sumbr" -> \%sumbrcount
+#
+# %testdata : name of test affecting this file -> \%testcount
+# %testfncdata: name of test affecting this file -> \%testfnccount
+# %testbrdata: name of test affecting this file -> \%testbrcount
+#
+# %testcount : line number -> execution count for a single test
+# %testfnccount: function name -> execution count for a single test
+# %testbrcount : line number -> branch coverage data for a single test
+# %sumcount : line number -> execution count for all tests
+# %sumfnccount : function name -> execution count for all tests
+# %sumbrcount : line number -> branch coverage data for all tests
+# %funcdata : function name -> line number
+# %checkdata : line number -> checksum of source code line
+# $brdata : vector of items: block, branch, taken
#
# Note that .info file sections referring to the same file and test name
# will automatically be combined by adding all execution counts.
@@ -834,15 +1235,26 @@
my $sumcount; # " "
my $funcdata; # " "
my $checkdata; # " "
+ my $testfncdata;
+ my $testfnccount;
+ my $sumfnccount;
+ my $testbrdata;
+ my $testbrcount;
+ my $sumbrcount;
my $line; # Current line read from .info file
my $testname; # Current test name
my $filename; # Current filename
my $hitcount; # Count for lines hit
my $count; # Execution count of current line
my $negative; # If set, warn about negative counts
- my $checksum; # Checksum of current line
+ my $changed_testname; # If set, warn about changed testname
+ my $line_checksum; # Checksum of current line
+ my $br_found;
+ my $br_hit;
local *INFO_HANDLE; # Filehandle for .info file
+ info("Reading data file $tracefile\n");
+
# Check if file exists and is readable
stat($_[0]);
if (!(-r _))
@@ -860,7 +1272,7 @@
if ($_[0] =~ /\.gz$/)
{
# Check for availability of GZIP tool
- system_no_output(1, "gunzip", "-h")
+ system_no_output(1, "gunzip" ,"-h")
and die("ERROR: gunzip command not available!\n");
# Check integrity of compressed file
@@ -870,12 +1282,12 @@
# Open compressed file
open(INFO_HANDLE, "gunzip -c $_[0]|")
- or die("ERROR: cannot start gunzip to uncompress ".
+ or die("ERROR: cannot start gunzip to decompress ".
"file $_[0]!\n");
}
else
{
- # Open uncompressed file
+ # Open decompressed file
open(INFO_HANDLE, $_[0])
or die("ERROR: cannot read file $_[0]!\n");
}
@@ -889,10 +1301,15 @@
# Switch statement
foreach ($line)
{
- /^TN:(\w*(,\w+)?)/ && do
+ /^TN:([^,]*)(,diff)?/ && do
{
# Test name information found
$testname = defined($1) ? $1 : "";
+ if ($testname =~ s/\W/_/g)
+ {
+ $changed_testname = 1;
+ }
+ $testname .= $2 if (defined($2));
last;
};
@@ -903,17 +1320,22 @@
$filename = $1;
$data = $result{$filename};
- ($testdata, $sumcount, $funcdata, $checkdata) =
+ ($testdata, $sumcount, $funcdata, $checkdata,
+ $testfncdata, $sumfnccount, $testbrdata,
+ $sumbrcount) =
get_info_entry($data);
if (defined($testname))
{
$testcount = $testdata->{$testname};
+ $testfnccount = $testfncdata->{$testname};
+ $testbrcount = $testbrdata->{$testname};
}
else
{
- my %new_hash;
- $testcount = \%new_hash;
+ $testcount = {};
+ $testfnccount = {};
+ $testbrcount = {};
}
last;
};
@@ -939,17 +1361,18 @@
# Store line checksum if available
if (defined($3))
{
- $checksum = substr($3, 1);
+ $line_checksum = substr($3, 1);
# Does it match a previous definition
if (defined($checkdata->{$1}) &&
- ($checkdata->{$1} ne $checksum))
+ ($checkdata->{$1} ne
+ $line_checksum))
{
die("ERROR: checksum mismatch ".
"at $filename:$1\n");
}
- $checkdata->{$1} = $checksum;
+ $checkdata->{$1} = $line_checksum;
}
last;
};
@@ -957,7 +1380,52 @@
/^FN:(\d+),([^,]+)/ && do
{
# Function data found, add to structure
- $funcdata->{$1} = $2;
+ $funcdata->{$2} = $1;
+
+ # Also initialize function call data
+ if (!defined($sumfnccount->{$2})) {
+ $sumfnccount->{$2} = 0;
+ }
+ if (defined($testname))
+ {
+ if (!defined($testfnccount->{$2})) {
+ $testfnccount->{$2} = 0;
+ }
+ }
+ last;
+ };
+
+ /^FNDA:(\d+),([^,]+)/ && do
+ {
+ # Function call count found, add to structure
+ # Add summary counts
+ $sumfnccount->{$2} += $1;
+
+ # Add test-specific counts
+ if (defined($testname))
+ {
+ $testfnccount->{$2} += $1;
+ }
+ last;
+ };
+
+ /^BRDA:(\d+),(\d+),(\d+),(\d+|-)/ && do {
+ # Branch coverage data found
+ my ($line, $block, $branch, $taken) =
+ ($1, $2, $3, $4);
+
+ $sumbrcount->{$line} =
+ br_ivec_push($sumbrcount->{$line},
+ $block, $branch, $taken);
+
+ # Add test-specific counts
+ if (defined($testname)) {
+ $testbrcount->{$line} =
+ br_ivec_push(
+ $testbrcount->{$line},
+ $block, $branch,
+ $taken);
+ }
last;
};
@@ -971,13 +1439,21 @@
{
$testdata->{$testname} =
$testcount;
- }
+ $testfncdata->{$testname} =
+ $testfnccount;
+ $testbrdata->{$testname} =
+ $testbrcount;
+ }
+
set_info_entry($data, $testdata,
$sumcount, $funcdata,
- $checkdata);
+ $checkdata, $testfncdata,
+ $sumfnccount,
+ $testbrdata,
+ $sumbrcount);
$result{$filename} = $data;
+ last;
}
-
};
# default
@@ -991,7 +1467,26 @@
{
$data = $result{$filename};
- ($testdata, $sumcount, $funcdata) = get_info_entry($data);
+ ($testdata, $sumcount, undef, undef, $testfncdata,
+ $sumfnccount, $testbrdata, $sumbrcount) =
+ get_info_entry($data);
+
+ # Filter out empty files
+ if (scalar(keys(%{$sumcount})) == 0)
+ {
+ delete($result{$filename});
+ next;
+ }
+ # Filter out empty test cases
+ foreach $testname (keys(%{$testdata}))
+ {
+ if (!defined($testdata->{$testname}) ||
+ scalar(keys(%{$testdata->{$testname}})) == 0)
+ {
+ delete($testdata->{$testname});
+ delete($testfncdata->{$testname});
+ }
+ }
$data->{"found"} = scalar(keys(%{$sumcount}));
$hitcount = 0;
@@ -1003,7 +1498,22 @@
$data->{"hit"} = $hitcount;
- $result{$filename} = $data;
+ # Get found/hit values for function call data
+ $data->{"f_found"} = scalar(keys(%{$sumfnccount}));
+ $hitcount = 0;
+
+ foreach (keys(%{$sumfnccount})) {
+ if ($sumfnccount->{$_} > 0) {
+ $hitcount++;
+ }
+ }
+ $data->{"f_hit"} = $hitcount;
+
+ # Get found/hit values for branch data
+ ($br_found, $br_hit) = get_br_found_and_hit($sumbrcount);
+
+ $data->{"b_found"} = $br_found;
+ $data->{"b_hit"} = $br_hit;
}
if (scalar(keys(%result)) == 0)
@@ -1015,6 +1525,11 @@
warn("WARNING: negative counts found in tracefile ".
"$tracefile\n");
}
+ if ($changed_testname)
+ {
+ warn("WARNING: invalid characters removed from testname in ".
+ "tracefile $tracefile\n");
+ }
return(\%result);
}
@@ -1026,7 +1541,8 @@
# Retrieve data from an entry of the structure generated by read_info_file().
# Return a list of references to hashes:
# (test data hash ref, sum count hash ref, funcdata hash ref, checkdata hash
-# ref, lines found, lines hit)
+# ref, testfncdata hash ref, sumfnccount hash ref, lines found, lines hit,
+# functions found, functions hit)
#
sub get_info_entry($)
@@ -1035,22 +1551,34 @@
my $sumcount_ref = $_[0]->{"sum"};
my $funcdata_ref = $_[0]->{"func"};
my $checkdata_ref = $_[0]->{"check"};
+ my $testfncdata = $_[0]->{"testfnc"};
+ my $sumfnccount = $_[0]->{"sumfnc"};
+ my $testbrdata = $_[0]->{"testbr"};
+ my $sumbrcount = $_[0]->{"sumbr"};
my $lines_found = $_[0]->{"found"};
my $lines_hit = $_[0]->{"hit"};
+ my $fn_found = $_[0]->{"f_found"};
+ my $fn_hit = $_[0]->{"f_hit"};
+ my $br_found = $_[0]->{"b_found"};
+ my $br_hit = $_[0]->{"b_hit"};
return ($testdata_ref, $sumcount_ref, $funcdata_ref, $checkdata_ref,
- $lines_found, $lines_hit);
+ $testfncdata, $sumfnccount, $testbrdata, $sumbrcount,
+ $lines_found, $lines_hit, $fn_found, $fn_hit,
+ $br_found, $br_hit);
}
#
# set_info_entry(hash_ref, testdata_ref, sumcount_ref, funcdata_ref,
-# checkdata_ref[,lines_found, lines_hit])
+# checkdata_ref, testfncdata_ref, sumfcncount_ref,
+# testbrdata_ref, sumbrcount_ref[,lines_found,
+# lines_hit, f_found, f_hit, $b_found, $b_hit])
#
# Update the hash referenced by HASH_REF with the provided data references.
#
-sub set_info_entry($$$$$;$$)
+sub set_info_entry($$$$$$$$$;$$$$$$)
{
my $data_ref = $_[0];
@@ -1058,9 +1586,526 @@
$data_ref->{"sum"} = $_[2];
$data_ref->{"func"} = $_[3];
$data_ref->{"check"} = $_[4];
-
- if (defined($_[5])) { $data_ref->{"found"} = $_[5]; }
- if (defined($_[6])) { $data_ref->{"hit"} = $_[6]; }
+ $data_ref->{"testfnc"} = $_[5];
+ $data_ref->{"sumfnc"} = $_[6];
+ $data_ref->{"testbr"} = $_[7];
+ $data_ref->{"sumbr"} = $_[8];
+
+ if (defined($_[9])) { $data_ref->{"found"} = $_[9]; }
+ if (defined($_[10])) { $data_ref->{"hit"} = $_[10]; }
+ if (defined($_[11])) { $data_ref->{"f_found"} = $_[11]; }
+ if (defined($_[12])) { $data_ref->{"f_hit"} = $_[12]; }
+ if (defined($_[13])) { $data_ref->{"b_found"} = $_[13]; }
+ if (defined($_[14])) { $data_ref->{"b_hit"} = $_[14]; }
+}
+
+
+#
+# add_counts(data1_ref, data2_ref)
+#
+# DATA1_REF and DATA2_REF are references to hashes containing a mapping
+#
+# line number -> execution count
+#
+# Return a list (RESULT_REF, LINES_FOUND, LINES_HIT) where RESULT_REF
+# is a reference to a hash containing the combined mapping in which
+# execution counts are added.
+#
+
+sub add_counts($$)
+{
+ my %data1 = %{$_[0]}; # Hash 1
+ my %data2 = %{$_[1]}; # Hash 2
+ my %result; # Resulting hash
+ my $line; # Current line iteration scalar
+ my $data1_count; # Count of line in hash1
+ my $data2_count; # Count of line in hash2
+ my $found = 0; # Total number of lines found
+ my $hit = 0; # Number of lines with a count > 0
+
+ foreach $line (keys(%data1))
+ {
+ $data1_count = $data1{$line};
+ $data2_count = $data2{$line};
+
+ # Add counts if present in both hashes
+ if (defined($data2_count)) { $data1_count += $data2_count; }
+
+ # Store sum in %result
+ $result{$line} = $data1_count;
+
+ $found++;
+ if ($data1_count > 0) { $hit++; }
+ }
+
+ # Add lines unique to data2
+ foreach $line (keys(%data2))
+ {
+ # Skip lines already in data1
+ if (defined($data1{$line})) { next; }
+
+ # Copy count from data2
+ $result{$line} = $data2{$line};
+
+ $found++;
+ if ($result{$line} > 0) { $hit++; }
+ }
+
+ return (\%result, $found, $hit);
+}
+
+
+#
+# merge_checksums(ref1, ref2, filename)
+#
+# REF1 and REF2 are references to hashes containing a mapping
+#
+# line number -> checksum
+#
+# Merge checksum lists defined in REF1 and REF2 and return reference to
+# resulting hash. Die if a checksum for a line is defined in both hashes
+# but does not match.
+#
+
+sub merge_checksums($$$)
+{
+ my $ref1 = $_[0];
+ my $ref2 = $_[1];
+ my $filename = $_[2];
+ my %result;
+ my $line;
+
+ foreach $line (keys(%{$ref1}))
+ {
+ if (defined($ref2->{$line}) &&
+ ($ref1->{$line} ne $ref2->{$line}))
+ {
+ die("ERROR: checksum mismatch at $filename:$line\n");
+ }
+ $result{$line} = $ref1->{$line};
+ }
+
+ foreach $line (keys(%{$ref2}))
+ {
+ $result{$line} = $ref2->{$line};
+ }
+
+ return \%result;
+}
+
+
+#
+# merge_func_data(funcdata1, funcdata2, filename)
+#
+
+sub merge_func_data($$$)
+{
+ my ($funcdata1, $funcdata2, $filename) = @_;
+ my %result;
+ my $func;
+
+ if (defined($funcdata1)) {
+ %result = %{$funcdata1};
+ }
+
+ foreach $func (keys(%{$funcdata2})) {
+ my $line1 = $result{$func};
+ my $line2 = $funcdata2->{$func};
+
+ if (defined($line1) && ($line1 != $line2)) {
+ warn("WARNING: function data mismatch at ".
+ "$filename:$line2\n");
+ next;
+ }
+ $result{$func} = $line2;
+ }
+
+ return \%result;
+}
+
+
+#
+# add_fnccount(fnccount1, fnccount2)
+#
+# Add function call count data. Return list (fnccount_added, f_found, f_hit)
+#
+
+sub add_fnccount($$)
+{
+ my ($fnccount1, $fnccount2) = @_;
+ my %result;
+ my $fn_found;
+ my $fn_hit;
+ my $function;
+
+ if (defined($fnccount1)) {
+ %result = %{$fnccount1};
+ }
+ foreach $function (keys(%{$fnccount2})) {
+ $result{$function} += $fnccount2->{$function};
+ }
+ $fn_found = scalar(keys(%result));
+ $fn_hit = 0;
+ foreach $function (keys(%result)) {
+ if ($result{$function} > 0) {
+ $fn_hit++;
+ }
+ }
+
+ return (\%result, $fn_found, $fn_hit);
+}
+
+#
+# add_testfncdata(testfncdata1, testfncdata2)
+#
+# Add function call count data for several tests. Return reference to
+# added_testfncdata.
+#
+
+sub add_testfncdata($$)
+{
+ my ($testfncdata1, $testfncdata2) = @_;
+ my %result;
+ my $testname;
+
+ foreach $testname (keys(%{$testfncdata1})) {
+ if (defined($testfncdata2->{$testname})) {
+ my $fnccount;
+
+ # Function call count data for this testname exists
+ # in both data sets: add
+ ($fnccount) = add_fnccount(
+ $testfncdata1->{$testname},
+ $testfncdata2->{$testname});
+ $result{$testname} = $fnccount;
+ next;
+ }
+ # Function call count data for this testname is unique to
+ # data set 1: copy
+ $result{$testname} = $testfncdata1->{$testname};
+ }
+
+ # Add count data for testnames unique to data set 2
+ foreach $testname (keys(%{$testfncdata2})) {
+ if (!defined($result{$testname})) {
+ $result{$testname} = $testfncdata2->{$testname};
+ }
+ }
+ return \%result;
+}
+
+
+#
+# brcount_to_db(brcount)
+#
+# Convert brcount data to the following format:
+#
+# db: line number -> block hash
+# block hash: block number -> branch hash
+# branch hash: branch number -> taken value
+#
+
+sub brcount_to_db($)
+{
+ my ($brcount) = @_;
+ my $line;
+ my $db;
+
+ # Add branches from first count to database
+ foreach $line (keys(%{$brcount})) {
+ my $brdata = $brcount->{$line};
+ my $i;
+ my $num = br_ivec_len($brdata);
+
+ for ($i = 0; $i < $num; $i++) {
+ my ($block, $branch, $taken) = br_ivec_get($brdata, $i);
+
+ $db->{$line}->{$block}->{$branch} = $taken;
+ }
+ }
+
+ return $db;
+}
+
+
+#
+# db_to_brcount(db)
+#
+# Convert branch coverage data back to brcount format.
+#
+
+sub db_to_brcount($)
+{
+ my ($db) = @_;
+ my $line;
+ my $brcount = {};
+ my $br_found = 0;
+ my $br_hit = 0;
+
+ # Convert database back to brcount format
+ foreach $line (sort({$a <=> $b} keys(%{$db}))) {
+ my $ldata = $db->{$line};
+ my $brdata;
+ my $block;
+
+ foreach $block (sort({$a <=> $b} keys(%{$ldata}))) {
+ my $bdata = $ldata->{$block};
+ my $branch;
+
+ foreach $branch (sort({$a <=> $b} keys(%{$bdata}))) {
+ my $taken = $bdata->{$branch};
+
+ $br_found++;
+ $br_hit++ if ($taken ne "-" && $taken > 0);
+ $brdata = br_ivec_push($brdata, $block,
+ $branch, $taken);
+ }
+ }
+ $brcount->{$line} = $brdata;
+ }
+
+ return ($brcount, $br_found, $br_hit);
+}
+
+
+#
+# combine_brcount(brcount1, brcount2, type)
+#
+# If add is BR_ADD, add branch coverage data and return list (brcount_added,
+# br_found, br_hit). If add is BR_SUB, subtract the taken values of brcount2
+# from brcount1 and return (brcount_sub, br_found, br_hit).
+#
+
+sub combine_brcount($$$)
+{
+ my ($brcount1, $brcount2, $type) = @_;
+ my $line;
+ my $block;
+ my $branch;
+ my $taken;
+ my $db;
+ my $br_found = 0;
+ my $br_hit = 0;
+ my $result;
+
+ # Convert branches from first count to database
+ $db = brcount_to_db($brcount1);
+ # Combine values from database and second count
+ foreach $line (keys(%{$brcount2})) {
+ my $brdata = $brcount2->{$line};
+ my $num = br_ivec_len($brdata);
+ my $i;
+
+ for ($i = 0; $i < $num; $i++) {
+ ($block, $branch, $taken) = br_ivec_get($brdata, $i);
+ my $new_taken = $db->{$line}->{$block}->{$branch};
+
+ if ($type == $BR_ADD) {
+ $new_taken = br_taken_add($new_taken, $taken);
+ } elsif ($type == $BR_SUB) {
+ $new_taken = br_taken_sub($new_taken, $taken);
+ }
+ $db->{$line}->{$block}->{$branch} = $new_taken
+ if (defined($new_taken));
+ }
+ }
+ # Convert database back to brcount format
+ ($result, $br_found, $br_hit) = db_to_brcount($db);
+
+ return ($result, $br_found, $br_hit);
+}
+
+
+#
+# add_testbrdata(testbrdata1, testbrdata2)
+#
+# Add branch coverage data for several tests. Return reference to
+# added_testbrdata.
+#
+
+sub add_testbrdata($$)
+{
+ my ($testbrdata1, $testbrdata2) = @_;
+ my %result;
+ my $testname;
+
+ foreach $testname (keys(%{$testbrdata1})) {
+ if (defined($testbrdata2->{$testname})) {
+ my $brcount;
+
+ # Branch coverage data for this testname exists
+ # in both data sets: add
+ ($brcount) = combine_brcount($testbrdata1->{$testname},
+ $testbrdata2->{$testname}, $BR_ADD);
+ $result{$testname} = $brcount;
+ next;
+ }
+ # Branch coverage data for this testname is unique to
+ # data set 1: copy
+ $result{$testname} = $testbrdata1->{$testname};
+ }
+
+ # Add count data for testnames unique to data set 2
+ foreach $testname (keys(%{$testbrdata2})) {
+ if (!defined($result{$testname})) {
+ $result{$testname} = $testbrdata2->{$testname};
+ }
+ }
+ return \%result;
+}
+
+
+#
+# combine_info_entries(entry_ref1, entry_ref2, filename)
+#
+# Combine .info data entry hashes referenced by ENTRY_REF1 and ENTRY_REF2.
+# Return reference to resulting hash.
+#
+
+sub combine_info_entries($$$)
+{
+ my $entry1 = $_[0]; # Reference to hash containing first entry
+ my $testdata1;
+ my $sumcount1;
+ my $funcdata1;
+ my $checkdata1;
+ my $testfncdata1;
+ my $sumfnccount1;
+ my $testbrdata1;
+ my $sumbrcount1;
+
+ my $entry2 = $_[1]; # Reference to hash containing second entry
+ my $testdata2;
+ my $sumcount2;
+ my $funcdata2;
+ my $checkdata2;
+ my $testfncdata2;
+ my $sumfnccount2;
+ my $testbrdata2;
+ my $sumbrcount2;
+
+ my %result; # Hash containing combined entry
+ my %result_testdata;
+ my $result_sumcount = {};
+ my $result_funcdata;
+ my $result_testfncdata;
+ my $result_sumfnccount;
+ my $result_testbrdata;
+ my $result_sumbrcount;
+ my $lines_found;
+ my $lines_hit;
+ my $fn_found;
+ my $fn_hit;
+ my $br_found;
+ my $br_hit;
+
+ my $testname;
+ my $filename = $_[2];
+
+ # Retrieve data
+ ($testdata1, $sumcount1, $funcdata1, $checkdata1, $testfncdata1,
+ $sumfnccount1, $testbrdata1, $sumbrcount1) = get_info_entry($entry1);
+ ($testdata2, $sumcount2, $funcdata2, $checkdata2, $testfncdata2,
+ $sumfnccount2, $testbrdata2, $sumbrcount2) = get_info_entry($entry2);
+
+ # Merge checksums
+ $checkdata1 = merge_checksums($checkdata1, $checkdata2, $filename);
+
+ # Combine funcdata
+ $result_funcdata = merge_func_data($funcdata1, $funcdata2, $filename);
+
+ # Combine function call count data
+ $result_testfncdata = add_testfncdata($testfncdata1, $testfncdata2);
+ ($result_sumfnccount, $fn_found, $fn_hit) =
+ add_fnccount($sumfnccount1, $sumfnccount2);
+
+ # Combine branch coverage data
+ $result_testbrdata = add_testbrdata($testbrdata1, $testbrdata2);
+ ($result_sumbrcount, $br_found, $br_hit) =
+ combine_brcount($sumbrcount1, $sumbrcount2, $BR_ADD);
+
+ # Combine testdata
+ foreach $testname (keys(%{$testdata1}))
+ {
+ if (defined($testdata2->{$testname}))
+ {
+ # testname is present in both entries, requires
+ # combination
+ ($result_testdata{$testname}) =
+ add_counts($testdata1->{$testname},
+ $testdata2->{$testname});
+ }
+ else
+ {
+ # testname only present in entry1, add to result
+ $result_testdata{$testname} = $testdata1->{$testname};
+ }
+
+ # update sum count hash
+ ($result_sumcount, $lines_found, $lines_hit) =
+ add_counts($result_sumcount,
+ $result_testdata{$testname});
+ }
+
+ foreach $testname (keys(%{$testdata2}))
+ {
+ # Skip testnames already covered by previous iteration
+ if (defined($testdata1->{$testname})) { next; }
+
+ # testname only present in entry2, add to result hash
+ $result_testdata{$testname} = $testdata2->{$testname};
+
+ # update sum count hash
+ ($result_sumcount, $lines_found, $lines_hit) =
+ add_counts($result_sumcount,
+ $result_testdata{$testname});
+ }
+
+ # Calculate resulting sumcount
+
+ # Store result
+ set_info_entry(\%result, \%result_testdata, $result_sumcount,
+ $result_funcdata, $checkdata1, $result_testfncdata,
+ $result_sumfnccount, $result_testbrdata,
+ $result_sumbrcount, $lines_found, $lines_hit,
+ $fn_found, $fn_hit, $br_found, $br_hit);
+
+ return(\%result);
+}
+
+
+#
+# combine_info_files(info_ref1, info_ref2)
+#
+# Combine .info data in hashes referenced by INFO_REF1 and INFO_REF2. Return
+# reference to resulting hash.
+#
+
+sub combine_info_files($$)
+{
+ my %hash1 = %{$_[0]};
+ my %hash2 = %{$_[1]};
+ my $filename;
+
+ foreach $filename (keys(%hash2))
+ {
+ if ($hash1{$filename})
+ {
+ # Entry already exists in hash1, combine them
+ $hash1{$filename} =
+ combine_info_entries($hash1{$filename},
+ $hash2{$filename},
+ $filename);
+ }
+ else
+ {
+ # Entry is unique in both hashes, simply add to
+ # resulting hash
+ $hash1{$filename} = $hash2{$filename};
+ }
+ }
+
+ return(\%hash1);
}
@@ -1212,6 +2257,7 @@
{
my %result;
my $test_name;
+ my $changed_testname;
local *TEST_HANDLE;
open(TEST_HANDLE, "<".$_[0])
@@ -1226,6 +2272,10 @@
{
# Store name for later use
$test_name = $1;
+ if ($test_name =~ s/\W/_/g)
+ {
+ $changed_testname = 1;
+ }
}
# Match lines beginning with TD:<whitespace(s)>
@@ -1247,6 +2297,12 @@
close(TEST_HANDLE);
+ if ($changed_testname)
+ {
+ warn("WARNING: invalid characters removed from testname in ".
+ "descriptions file $_[0]\n");
+ }
+
return \%result;
}
@@ -1310,13 +2366,17 @@
sub create_sub_dir($)
{
- system("mkdir", "-p" ,$_[0])
- and die("ERROR: cannot create directory $_!\n");
+ my ($dir) = @_;
+
+ system("mkdir", "-p" ,$dir)
+ and die("ERROR: cannot create directory $dir!\n");
}
#
-# write_description_file(descriptions, overall_found, overall_hit)
+# write_description_file(descriptions, overall_found, overall_hit,
+# total_fn_found, total_fn_hit, total_br_found,
+# total_br_hit)
#
# Write HTML file containing all test case descriptions. DESCRIPTIONS is a
# reference to a hash containing a mapping
@@ -1326,19 +2386,22 @@
# Die on error.
#
-sub write_description_file($$$)
+sub write_description_file($$$$$$$)
{
my %description = %{$_[0]};
my $found = $_[1];
my $hit = $_[2];
+ my $fn_found = $_[3];
+ my $fn_hit = $_[4];
+ my $br_found = $_[5];
+ my $br_hit = $_[6];
my $test_name;
local *HTML_HANDLE;
- open(HTML_HANDLE, ">descriptions.html")
- or die("ERROR: cannot open descriptions.html for writing!\n");
-
+ html_create(*HTML_HANDLE,"descriptions.$html_ext");
write_html_prolog(*HTML_HANDLE, "", "LCOV - test case descriptions");
- write_header(*HTML_HANDLE, 3, "", "", $found, $hit);
+ write_header(*HTML_HANDLE, 3, "", "", $found, $hit, $fn_found,
+ $fn_hit, $br_found, $br_hit, 0);
write_test_table_prolog(*HTML_HANDLE,
"Test case descriptions - alphabetical list");
@@ -1352,7 +2415,7 @@
write_test_table_epilog(*HTML_HANDLE);
write_html_epilog(*HTML_HANDLE, "");
- close(HTML_HANDLE);
+ close(*HTML_HANDLE);
}
@@ -1401,8 +2464,8 @@
0x00, 0x00, 0x00, 0xa2, 0x7a, 0xda, 0x7e, 0x00, 0x00, 0x00,
0x0a, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x60, 0x00,
0x00, 0x00, 0x02, 0x00, 0x01, 0xe5, 0x27, 0xde, 0xfc, 0x00,
- 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60,
- 0x82];
+ 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60,
+ 0x82];
$data{"emerald.png"} =
[0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00,
0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01,
@@ -1453,7 +2516,19 @@
0x54, 0x78, 0x9c, 0x63, 0x60, 0x00, 0x00, 0x00, 0x02, 0x00,
0x01, 0x48, 0xaf, 0xa4, 0x71, 0x00, 0x00, 0x00, 0x00, 0x49,
0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82];
-
+ $data{"updown.png"} =
+ [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00,
+ 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x0a,
+ 0x00, 0x00, 0x00, 0x0e, 0x08, 0x06, 0x00, 0x00, 0x00, 0x16,
+ 0xa3, 0x8d, 0xab, 0x00, 0x00, 0x00, 0x3c, 0x49, 0x44, 0x41,
+ 0x54, 0x28, 0xcf, 0x63, 0x60, 0x40, 0x03, 0xff, 0xa1, 0x00,
+ 0x5d, 0x9c, 0x11, 0x5d, 0x11, 0x8a, 0x24, 0x23, 0x23, 0x23,
+ 0x86, 0x42, 0x6c, 0xa6, 0x20, 0x2b, 0x66, 0xc4, 0xa7, 0x08,
+ 0x59, 0x31, 0x23, 0x21, 0x45, 0x30, 0xc0, 0xc4, 0x30, 0x60,
+ 0x80, 0xfa, 0x6e, 0x24, 0x3e, 0x78, 0x48, 0x0a, 0x70, 0x62,
+ 0xa2, 0x90, 0x81, 0xd8, 0x44, 0x01, 0x00, 0xe9, 0x5c, 0x2f,
+ 0xf5, 0xe2, 0x9d, 0x0f, 0xf9, 0x00, 0x00, 0x00, 0x00, 0x49,
+ 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82] if ($sort);
foreach (keys(%data))
{
open(PNG_HANDLE, ">".$_)
@@ -1466,6 +2541,28 @@
#
+# write_htaccess_file()
+#
+
+sub write_htaccess_file()
+{
+ local *HTACCESS_HANDLE;
+ my $htaccess_data;
+
+ open(*HTACCESS_HANDLE, ">.htaccess")
+ or die("ERROR: cannot open .htaccess for writing!\n");
+
+ $htaccess_data = (<<"END_OF_HTACCESS")
+AddEncoding x-gzip .html
+END_OF_HTACCESS
+ ;
+
+ print(HTACCESS_HANDLE $htaccess_data);
+ close(*HTACCESS_HANDLE);
+}
+
+
+#
# write_css_file()
#
# Write the cascading style sheet file gcov.css to the current directory.
@@ -1495,318 +2592,522 @@
/* All views: initial background and text color */
body
{
- color: #000000;
+ color: #000000;
background-color: #FFFFFF;
}
-
-
+
/* All views: standard link format*/
a:link
{
- color: #284FA8;
+ color: #284FA8;
text-decoration: underline;
}
-
-
+
/* All views: standard link - visited format */
a:visited
{
- color: #00CB40;
+ color: #00CB40;
text-decoration: underline;
}
-
-
+
/* All views: standard link - activated format */
a:active
{
- color: #FF0040;
+ color: #FF0040;
text-decoration: underline;
}
-
-
+
/* All views: main title format */
td.title
{
- text-align: center;
+ text-align: center;
padding-bottom: 10px;
- font-family: sans-serif;
- font-size: 20pt;
- font-style: italic;
- font-weight: bold;
- }
-
-
+ font-family: sans-serif;
+ font-size: 20pt;
+ font-style: italic;
+ font-weight: bold;
+ }
+
/* All views: header item format */
td.headerItem
{
- text-align: right;
+ text-align: right;
padding-right: 6px;
- font-family: sans-serif;
- font-weight: bold;
- }
-
-
+ font-family: sans-serif;
+ font-weight: bold;
+ vertical-align: top;
+ white-space: nowrap;
+ }
+
/* All views: header item value format */
td.headerValue
{
- text-align: left;
- color: #284FA8;
+ text-align: left;
+ color: #284FA8;
+ font-family: sans-serif;
+ font-weight: bold;
+ white-space: nowrap;
+ }
+
+ /* All views: header item coverage table heading */
+ td.headerCovTableHead
+ {
+ text-align: center;
+ padding-right: 6px;
+ padding-left: 6px;
+ padding-bottom: 0px;
+ font-family: sans-serif;
+ font-size: 80%;
+ white-space: nowrap;
+ }
+
+ /* All views: header item coverage table entry */
+ td.headerCovTableEntry
+ {
+ text-align: right;
+ color: #284FA8;
+ font-family: sans-serif;
+ font-weight: bold;
+ white-space: nowrap;
+ padding-left: 12px;
+ padding-right: 4px;
+ background-color: #DAE7FE;
+ }
+
+ /* All views: header item coverage table entry for high coverage rate */
+ td.headerCovTableEntryHi
+ {
+ text-align: right;
+ color: #000000;
font-family: sans-serif;
font-weight: bold;
- }
-
-
+ white-space: nowrap;
+ padding-left: 12px;
+ padding-right: 4px;
+ background-color: #A7FC9D;
+ }
+
+ /* All views: header item coverage table entry for medium coverage rate */
+ td.headerCovTableEntryMed
+ {
+ text-align: right;
+ color: #000000;
+ font-family: sans-serif;
+ font-weight: bold;
+ white-space: nowrap;
+ padding-left: 12px;
+ padding-right: 4px;
+ background-color: #FFEA20;
+ }
+
+ /* All views: header item coverage table entry for ow coverage rate */
+ td.headerCovTableEntryLo
+ {
+ text-align: right;
+ color: #000000;
+ font-family: sans-serif;
+ font-weight: bold;
+ white-space: nowrap;
+ padding-left: 12px;
+ padding-right: 4px;
+ background-color: #FF0000;
+ }
+
+ /* All views: header legend value for legend entry */
+ td.headerValueLeg
+ {
+ text-align: left;
+ color: #000000;
+ font-family: sans-serif;
+ font-size: 80%;
+ white-space: nowrap;
+ padding-top: 4px;
+ }
+
/* All views: color of horizontal ruler */
td.ruler
{
background-color: #6688D4;
}
-
-
+
/* All views: version string format */
td.versionInfo
{
- text-align: center;
- padding-top: 2px;
- font-family: sans-serif;
- font-style: italic;
- }
-
-
+ text-align: center;
+ padding-top: 2px;
+ font-family: sans-serif;
+ font-style: italic;
+ }
+
/* Directory view/File view (all)/Test case descriptions:
table headline format */
td.tableHead
{
- text-align: center;
- color: #FFFFFF;
+ text-align: center;
+ color: #FFFFFF;
background-color: #6688D4;
- font-family: sans-serif;
- font-size: 120%;
- font-weight: bold;
- }
-
-
+ font-family: sans-serif;
+ font-size: 120%;
+ font-weight: bold;
+ white-space: nowrap;
+ padding-left: 4px;
+ padding-right: 4px;
+ }
+
+ span.tableHeadSort
+ {
+ padding-right: 4px;
+ }
+
/* Directory view/File view (all): filename entry format */
td.coverFile
{
- text-align: left;
- padding-left: 10px;
- padding-right: 20px;
- color: #284FA8;
+ text-align: left;
+ padding-left: 10px;
+ padding-right: 20px;
+ color: #284FA8;
background-color: #DAE7FE;
- font-family: monospace;
- }
-
-
+ font-family: monospace;
+ }
+
/* Directory view/File view (all): bar-graph entry format*/
td.coverBar
{
- padding-left: 10px;
- padding-right: 10px;
+ padding-left: 10px;
+ padding-right: 10px;
background-color: #DAE7FE;
}
-
-
+
/* Directory view/File view (all): bar-graph outline color */
td.coverBarOutline
{
background-color: #000000;
}
-
-
+
/* Directory view/File view (all): percentage entry for files with
high coverage rate */
td.coverPerHi
{
- text-align: right;
- padding-left: 10px;
- padding-right: 10px;
- background-color: #DAE7FE;
- font-weight: bold;
- }
-
-
+ text-align: right;
+ padding-left: 10px;
+ padding-right: 10px;
+ background-color: #A7FC9D;
+ font-weight: bold;
+ font-family: sans-serif;
+ }
+
/* Directory view/File view (all): line count entry for files with
high coverage rate */
td.coverNumHi
{
- text-align: right;
- padding-left: 10px;
- padding-right: 10px;
- background-color: #DAE7FE;
- }
-
-
+ text-align: right;
+ padding-left: 10px;
+ padding-right: 10px;
+ background-color: #A7FC9D;
+ white-space: nowrap;
+ font-family: sans-serif;
+ }
+
/* Directory view/File view (all): percentage entry for files with
medium coverage rate */
td.coverPerMed
{
- text-align: right;
- padding-left: 10px;
- padding-right: 10px;
+ text-align: right;
+ padding-left: 10px;
+ padding-right: 10px;
background-color: #FFEA20;
- font-weight: bold;
- }
-
-
+ font-weight: bold;
+ font-family: sans-serif;
+ }
+
/* Directory view/File view (all): line count entry for files with
medium coverage rate */
td.coverNumMed
{
- text-align: right;
- padding-left: 10px;
- padding-right: 10px;
+ text-align: right;
+ padding-left: 10px;
+ padding-right: 10px;
background-color: #FFEA20;
- }
-
-
+ white-space: nowrap;
+ font-family: sans-serif;
+ }
+
/* Directory view/File view (all): percentage entry for files with
low coverage rate */
td.coverPerLo
{
- text-align: right;
- padding-left: 10px;
- padding-right: 10px;
+ text-align: right;
+ padding-left: 10px;
+ padding-right: 10px;
background-color: #FF0000;
- font-weight: bold;
- }
-
-
+ font-weight: bold;
+ font-family: sans-serif;
+ }
+
/* Directory view/File view (all): line count entry for files with
low coverage rate */
td.coverNumLo
{
- text-align: right;
- padding-left: 10px;
- padding-right: 10px;
+ text-align: right;
+ padding-left: 10px;
+ padding-right: 10px;
background-color: #FF0000;
- }
-
-
+ white-space: nowrap;
+ font-family: sans-serif;
+ }
+
/* File view (all): "show/hide details" link format */
a.detail:link
{
color: #B8D0FF;
- }
-
-
+ font-size:80%;
+ }
+
/* File view (all): "show/hide details" link - visited format */
a.detail:visited
{
color: #B8D0FF;
- }
-
-
+ font-size:80%;
+ }
+
/* File view (all): "show/hide details" link - activated format */
a.detail:active
{
color: #FFFFFF;
- }
-
-
- /* File view (detail): test name table headline format */
- td.testNameHead
- {
- text-align: right;
- padding-right: 10px;
- background-color: #DAE7FE;
- font-family: sans-serif;
- font-weight: bold;
- }
-
-
- /* File view (detail): test lines table headline format */
- td.testLinesHead
- {
- text-align: center;
- background-color: #DAE7FE;
- font-family: sans-serif;
- font-weight: bold;
- }
-
-
+ font-size:80%;
+ }
+
/* File view (detail): test name entry */
td.testName
{
- text-align: right;
- padding-right: 10px;
+ text-align: right;
+ padding-right: 10px;
background-color: #DAE7FE;
- }
-
-
+ font-family: sans-serif;
+ }
+
/* File view (detail): test percentage entry */
td.testPer
{
- text-align: right;
- padding-left: 10px;
- padding-right: 10px;
+ text-align: right;
+ padding-left: 10px;
+ padding-right: 10px;
background-color: #DAE7FE;
- }
-
-
+ font-family: sans-serif;
+ }
+
/* File view (detail): test lines count entry */
td.testNum
{
- text-align: right;
- padding-left: 10px;
- padding-right: 10px;
+ text-align: right;
+ padding-left: 10px;
+ padding-right: 10px;
background-color: #DAE7FE;
- }
-
-
+ font-family: sans-serif;
+ }
+
/* Test case descriptions: test name format*/
dt
{
font-family: sans-serif;
font-weight: bold;
}
-
-
+
/* Test case descriptions: description table body */
td.testDescription
{
- padding-top: 10px;
- padding-left: 30px;
- padding-bottom: 10px;
- padding-right: 30px;
+ padding-top: 10px;
+ padding-left: 30px;
+ padding-bottom: 10px;
+ padding-right: 30px;
+ background-color: #DAE7FE;
+ }
+
+ /* Source code view: function entry */
+ td.coverFn
+ {
+ text-align: left;
+ padding-left: 10px;
+ padding-right: 20px;
+ color: #284FA8;
background-color: #DAE7FE;
- }
-
+ font-family: monospace;
+ }
+
+ /* Source code view: function entry zero count*/
+ td.coverFnLo
+ {
+ text-align: right;
+ padding-left: 10px;
+ padding-right: 10px;
+ background-color: #FF0000;
+ font-weight: bold;
+ font-family: sans-serif;
+ }
+
+ /* Source code view: function entry nonzero count*/
+ td.coverFnHi
+ {
+ text-align: right;
+ padding-left: 10px;
+ padding-right: 10px;
+ background-color: #DAE7FE;
+ font-weight: bold;
+ font-family: sans-serif;
+ }
/* Source code view: source code format */
pre.source
{
font-family: monospace;
white-space: pre;
- }
-
+ margin-top: 2px;
+ }
+
/* Source code view: line number format */
span.lineNum
{
background-color: #EFE383;
}
-
-
+
/* Source code view: format for lines which were executed */
+ td.lineCov,
span.lineCov
{
background-color: #CAD7FE;
}
-
-
+
+ /* Source code view: format for Cov legend */
+ span.coverLegendCov
+ {
+ padding-left: 10px;
+ padding-right: 10px;
+ padding-bottom: 2px;
+ background-color: #CAD7FE;
+ }
+
/* Source code view: format for lines which were not executed */
+ td.lineNoCov,
span.lineNoCov
{
background-color: #FF6230;
}
-
-
+
+ /* Source code view: format for NoCov legend */
+ span.coverLegendNoCov
+ {
+ padding-left: 10px;
+ padding-right: 10px;
+ padding-bottom: 2px;
+ background-color: #FF6230;
+ }
+
+ /* Source code view (function table): standard link - visited format */
+ td.lineNoCov > a:visited,
+ td.lineCov > a:visited
+ {
+ color: black;
+ text-decoration: underline;
+ }
+
/* Source code view: format for lines which were executed only in a
previous version */
span.lineDiffCov
{
background-color: #B5F7AF;
}
+
+ /* Source code view: format for branches which were executed
+ * and taken */
+ span.branchCov
+ {
+ background-color: #CAD7FE;
+ }
+
+ /* Source code view: format for branches which were executed
+ * but not taken */
+ span.branchNoCov
+ {
+ background-color: #FF6230;
+ }
+
+ /* Source code view: format for branches which were not executed */
+ span.branchNoExec
+ {
+ background-color: #FF6230;
+ }
+
+ /* Source code view: format for the source code heading line */
+ pre.sourceHeading
+ {
+ white-space: pre;
+ font-family: monospace;
+ font-weight: bold;
+ margin: 0px;
+ }
+
+ /* All views: header legend value for low rate */
+ td.headerValueLegL
+ {
+ font-family: sans-serif;
+ text-align: center;
+ white-space: nowrap;
+ padding-left: 4px;
+ padding-right: 2px;
+ background-color: #FF0000;
+ font-size: 80%;
+ }
+
+ /* All views: header legend value for med rate */
+ td.headerValueLegM
+ {
+ font-family: sans-serif;
+ text-align: center;
+ white-space: nowrap;
+ padding-left: 2px;
+ padding-right: 2px;
+ background-color: #FFEA20;
+ font-size: 80%;
+ }
+
+ /* All views: header legend value for hi rate */
+ td.headerValueLegH
+ {
+ font-family: sans-serif;
+ text-align: center;
+ white-space: nowrap;
+ padding-left: 2px;
+ padding-right: 4px;
+ background-color: #A7FC9D;
+ font-size: 80%;
+ }
+
+ /* All views except source code view: legend format for low coverage */
+ span.coverLegendCovLo
+ {
+ padding-left: 10px;
+ padding-right: 10px;
+ padding-top: 2px;
+ background-color: #FF0000;
+ }
+
+ /* All views except source code view: legend format for med coverage */
+ span.coverLegendCovMed
+ {
+ padding-left: 10px;
+ padding-right: 10px;
+ padding-top: 2px;
+ background-color: #FFEA20;
+ }
+
+ /* All views except source code view: legend format for hi coverage */
+ span.coverLegendCovHi
+ {
+ padding-left: 10px;
+ padding-right: 10px;
+ padding-top: 2px;
+ background-color: #A7FC9D;
+ }
END_OF_CSS
;
@@ -1847,9 +3148,8 @@
$remainder = sprintf("%d", 100-$width);
# Decide which .png file to use
- if ($rate < $med_limit) { $png_name = "ruby.png"; }
- elsif ($rate < $hi_limit) { $png_name = "amber.png"; }
- else { $png_name = "emerald.png"; }
+ $png_name = $rate_png[classify_rate($_[1], $_[2], $med_limit,
+ $hi_limit)];
if ($width == 0)
{
@@ -1883,6 +3183,29 @@
return($graph_code);
}
+#
+# sub classify_rate(found, hit, med_limit, high_limit)
+#
+# Return 0 for low rate, 1 for medium rate and 2 for hi rate.
+#
+
+sub classify_rate($$$$)
+{
+ my ($found, $hit, $med, $hi) = @_;
+ my $rate;
+
+ if ($found == 0) {
+ return 2;
+ }
+ $rate = $hit * 100 / $found;
+ if ($rate < $med) {
+ return 0;
+ } elsif ($rate < $hi) {
+ return 1;
+ }
+ return 2;
+}
+
#
# write_html(filehandle, html_code)
@@ -1914,28 +3237,15 @@
sub write_html_prolog(*$$)
{
+ my $basedir = $_[1];
my $pagetitle = $_[2];
-
-
- # *************************************************************
-
- write_html($_[0], <<END_OF_HTML)
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
-
- <html lang="en">
-
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
- <title>$pagetitle</title>
- <link rel="stylesheet" type="text/css" href="$_[1]gcov.css">
- </head>
-
- <body>
-
-END_OF_HTML
- ;
-
- # *************************************************************
+ my $prolog;
+
+ $prolog = $html_prolog;
+ $prolog =~ s/\@pagetitle\@/$pagetitle/g;
+ $prolog =~ s/\@basedir\@/$basedir/g;
+
+ write_html($_[0], $prolog);
}
@@ -1965,54 +3275,40 @@
#
-# write_header_line(filehandle, item1, value1, [item2, value2])
-#
-# Write a header line, containing of either one or two pairs "header item"
-# and "header value".
-#
-
-sub write_header_line(*$$;$$)
+# write_header_line(handle, content)
+#
+# Write a header line with the specified table contents.
+#
+
+sub write_header_line(*@)
{
- my $item1 = $_[1];
- my $value1 = $_[2];
-
- # Use GOTO to prevent indenting HTML with more than one tabs
- if (scalar(@_) > 3) { goto two_items }
-
- # *************************************************************
-
- write_html($_[0], <<END_OF_HTML)
- <tr>
- <td class="headerItem" width="20%">$item1:</td>
- <td class="headerValue" width="80%" colspan=4>$value1</td>
- </tr>
-END_OF_HTML
- ;
-
- return();
-
- # *************************************************************
-
-
-two_items:
- my $item2 = $_[3];
- my $value2 = $_[4];
-
-
- # *************************************************************
-
- write_html($_[0], <<END_OF_HTML)
- <tr>
- <td class="headerItem" width="20%">$item1:</td>
- <td class="headerValue" width="20%">$value1</td>
- <td width="20%"></td>
- <td class="headerItem" width="20%">$item2:</td>
- <td class="headerValue" width="20%">$value2</td>
- </tr>
-END_OF_HTML
- ;
-
- # *************************************************************
+ my ($handle, @content) = @_;
+ my $entry;
+
+ write_html($handle, " <tr>\n");
+ foreach $entry (@content) {
+ my ($width, $class, $text, $colspan) = @{$entry};
+
+ if (defined($width)) {
+ $width = " width=\"$width\"";
+ } else {
+ $width = "";
+ }
+ if (defined($class)) {
+ $class = " class=\"$class\"";
+ } else {
+ $class = "";
+ }
+ if (defined($colspan)) {
+ $colspan = " colspan=\"$colspan\"";
+ } else {
+ $colspan = "";
+ }
+ $text = "" if (!defined($text));
+ write_html($handle,
+ " <td$width$class$colspan>$text</td>\n");
+ }
+ write_html($handle, " </tr>\n");
}
@@ -2027,9 +3323,11 @@
# *************************************************************
write_html($_[0], <<END_OF_HTML)
+ <tr><td><img src="$_[1]glass.png" width=3 height=3 alt=""></td></tr>
</table>
</td>
</tr>
+
<tr><td class="ruler"><img src="$_[1]glass.png" width=3 height=3 alt=""></td></tr>
</table>
@@ -2041,148 +3339,172 @@
#
-# write_file_table_prolog(filehandle, left_heading, right_heading)
+# write_file_table_prolog(handle, file_heading, ([heading, num_cols], ...))
#
# Write heading for file table.
#
-sub write_file_table_prolog(*$$)
+sub write_file_table_prolog(*$@)
{
- # *************************************************************
-
- write_html($_[0], <<END_OF_HTML)
+ my ($handle, $file_heading, @columns) = @_;
+ my $num_columns = 0;
+ my $file_width;
+ my $col;
+ my $width;
+
+ $width = 20 if (scalar(@columns) == 1);
+ $width = 10 if (scalar(@columns) == 2);
+ $width = 8 if (scalar(@columns) > 2);
+
+ foreach $col (@columns) {
+ my ($heading, $cols) = @{$col};
+
+ $num_columns += $cols;
+ }
+ $file_width = 100 - $num_columns * $width;
+
+ # Table definition
+ write_html($handle, <<END_OF_HTML);
<center>
- <table width="80%" cellpadding=2 cellspacing=1 border=0>
+ <table width="80%" cellpadding=1 cellspacing=1 border=0>
<tr>
- <td width="50%"><br></td>
- <td width="15%"></td>
- <td width="15%"></td>
- <td width="20%"></td>
+ <td width="$file_width%"><br></td>
+END_OF_HTML
+ # Empty first row
+ foreach $col (@columns) {
+ my ($heading, $cols) = @{$col};
+
+ while ($cols-- > 0) {
+ write_html($handle, <<END_OF_HTML);
+ <td width="$width%"></td>
+END_OF_HTML
+ }
+ }
+ # Next row
+ write_html($handle, <<END_OF_HTML);
</tr>
<tr>
- <td class="tableHead">$_[1]</td>
- <td class="tableHead" colspan=3>$_[2]</td>
+ <td class="tableHead">$file_heading</td>
+END_OF_HTML
+ # Heading row
+ foreach $col (@columns) {
+ my ($heading, $cols) = @{$col};
+ my $colspan = "";
+
+ $colspan = " colspan=$cols" if ($cols > 1);
+ write_html($handle, <<END_OF_HTML);
+ <td class="tableHead"$colspan>$heading</td>
+END_OF_HTML
+ }
+ write_html($handle, <<END_OF_HTML);
+ </tr>
+END_OF_HTML
+}
+
+
+# write_file_table_entry(handle, base_dir, filename, page_link,
+# ([ found, hit, med_limit, hi_limit, graph ], ..)
+#
+# Write an entry of the file table.
+#
+
+sub write_file_table_entry(*$$$@)
+{
+ my ($handle, $base_dir, $filename, $page_link, @entries) = @_;
+ my $file_code;
+ my $entry;
+
+ # Add link to source if provided
+ if (defined($page_link) && $page_link ne "") {
+ $file_code = "<a href=\"$page_link\">$filename</a>";
+ } else {
+ $file_code = $filename;
+ }
+
+ # First column: filename
+ write_html($handle, <<END_OF_HTML);
+ <tr>
+ <td class="coverFile">$file_code</td>
+END_OF_HTML
+ # Columns as defined
+ foreach $entry (@entries) {
+ my ($found, $hit, $med, $hi, $graph) = @{$entry};
+ my $bar_graph;
+ my $class;
+ my $rate;
+
+ # Generate bar graph if requested
+ if ($graph) {
+ $bar_graph = get_bar_graph_code($base_dir, $found,
+ $hit);
+ write_html($handle, <<END_OF_HTML);
+ <td class="coverBar" align="center">
+ $bar_graph
+ </td>
+END_OF_HTML
+ }
+ # Get rate color and text
+ if ($found == 0) {
+ $rate = "-";
+ $class = "Hi";
+ } else {
+ $rate = sprintf("%.1f %%", $hit * 100 / $found);
+ $class = $rate_name[classify_rate($found, $hit,
+ $med, $hi)];
+ }
+ write_html($handle, <<END_OF_HTML);
+ <td class="coverPer$class">$rate</td>
+ <td class="coverNum$class">$hit / $found</td>
+END_OF_HTML
+ }
+ # End of row
+ write_html($handle, <<END_OF_HTML);
+ </tr>
+END_OF_HTML
+}
+
+
+#
+# write_file_table_detail_entry(filehandle, test_name, ([found, hit], ...))
+#
+# Write entry for detail section in file table.
+#
+
+sub write_file_table_detail_entry(*$@)
+{
+ my ($handle, $test, @entries) = @_;
+ my $entry;
+
+ if ($test eq "") {
+ $test = "<span style=\"font-style:italic\"><unnamed></span>";
+ } elsif ($test =~ /^(.*),diff$/) {
+ $test = $1." (converted)";
+ }
+ # Testname
+ write_html($handle, <<END_OF_HTML);
+ <tr>
+ <td class="testName" colspan=2>$test</td>
+END_OF_HTML
+ # Test data
+ foreach $entry (@entries) {
+ my ($found, $hit) = @{$entry};
+ my $rate = "-";
+
+ if ($found > 0) {
+ $rate = sprintf("%.1f %%", $hit * 100 / $found);
+ }
+ write_html($handle, <<END_OF_HTML);
+ <td class="testPer">$rate</td>
+ <td class="testNum">$hit / $found</td>
+END_OF_HTML
+ }
+
+ write_html($handle, <<END_OF_HTML);
</tr>
END_OF_HTML
- ;
-
- # *************************************************************
-}
-
-
-#
-# write_file_table_entry(filehandle, cover_filename, cover_bar_graph,
-# cover_found, cover_hit)
-#
-# Write an entry of the file table.
-#
-
-sub write_file_table_entry(*$$$$)
-{
- my $rate;
- my $rate_string;
- my $classification = "Lo";
-
- if ($_[3]>0)
- {
- $rate = $_[4] * 100 / $_[3];
- $rate_string = sprintf("%.1f", $rate)." %";
-
- if ($rate < $med_limit) { $classification = "Lo"; }
- elsif ($rate < $hi_limit) { $classification = "Med"; }
- else { $classification = "Hi"; }
- }
- else
- {
- $rate_string = "undefined";
- }
-
- # *************************************************************
-
- write_html($_[0], <<END_OF_HTML)
- <tr>
- <td class="coverFile">$_[1]</td>
- <td class="coverBar" align="center">
- $_[2]
- </td>
- <td class="coverPer$classification">$rate_string</td>
- <td class="coverNum$classification">$_[4] / $_[3] lines</td>
- </tr>
-
-END_OF_HTML
- ;
-
- # *************************************************************
-}
-
-
-#
-# write_file_table_detail_heading(filehandle, left_heading, right_heading)
-#
-# Write heading for detail section in file table.
-#
-
-sub write_file_table_detail_heading(*$$)
-{
- # *************************************************************
-
- write_html($_[0], <<END_OF_HTML)
- <tr>
- <td class="testNameHead" colspan=2>$_[1]</td>
- <td class="testLinesHead" colspan=2>$_[2]</td>
- </tr>
-
-END_OF_HTML
- ;
-
- # *************************************************************
-}
-
-
-#
-# write_file_table_detail_entry(filehandle, test_name, cover_found, cover_hit)
-#
-# Write entry for detail section in file table.
-#
-
-sub write_file_table_detail_entry(*$$$)
-{
- my $rate;
- my $name = $_[1];
-
- if ($_[2]>0)
- {
- $rate = sprintf("%.1f", $_[3]*100/$_[2])." %";
- }
- else
- {
- $rate = "undefined";
- }
-
- if ($name =~ /^(.*),diff$/)
- {
- $name = $1." (converted)";
- }
-
- if ($name eq "")
- {
- $name = "<span style=\"font-style:italic\"><unnamed></span>";
- }
-
- # *************************************************************
-
- write_html($_[0], <<END_OF_HTML)
- <tr>
- <td class="testName" colspan=2>$name</td>
- <td class="testPer">$rate</td>
- <td class="testNum">$_[3] / $_[2] lines</td>
- </tr>
-
-END_OF_HTML
- ;
# *************************************************************
}
@@ -2287,6 +3609,17 @@
}
+sub fmt_centered($$)
+{
+ my ($width, $text) = @_;
+ my $w0 = length($text);
+ my $w1 = int(($width - $w0) / 2);
+ my $w2 = $width - $w0 - $w1;
+
+ return (" "x$w1).$text.(" "x$w2);
+}
+
+
#
# write_source_prolog(filehandle)
#
@@ -2295,6 +3628,15 @@
sub write_source_prolog(*)
{
+ my $lineno_heading = " ";
+ my $branch_heading = "";
+ my $line_heading = fmt_centered($line_field_width, "Line data");
+ my $source_heading = " Source code";
+
+ if ($br_coverage) {
+ $branch_heading = fmt_centered($br_field_width, "Branch data").
+ " ";
+ }
# *************************************************************
write_html($_[0], <<END_OF_HTML)
@@ -2303,7 +3645,9 @@
<td><br></td>
</tr>
<tr>
- <td><pre class="source">
+ <td>
+<pre class="sourceHeading">${lineno_heading}${branch_heading}${line_heading} ${source_heading}</pre>
+<pre class="source">
END_OF_HTML
;
@@ -2312,50 +3656,251 @@
#
-# write_source_line(filehandle, line_num, source, hit_count, converted)
+# get_branch_blocks(brdata)
+#
+# Group branches that belong to the same basic block.
+#
+# Returns: [block1, block2, ...]
+# block: [branch1, branch2, ...]
+# branch: [block_num, branch_num, taken_count, text_length, open, close]
+#
+
+sub get_branch_blocks($)
+{
+ my ($brdata) = @_;
+ my $last_block_num;
+ my $block = [];
+ my @blocks;
+ my $i;
+ my $num = br_ivec_len($brdata);
+
+ # Group branches
+ for ($i = 0; $i < $num; $i++) {
+ my ($block_num, $branch, $taken) = br_ivec_get($brdata, $i);
+ my $br;
+
+ if (defined($last_block_num) && $block_num != $last_block_num) {
+ push(@blocks, $block);
+ $block = [];
+ }
+ $br = [$block_num, $branch, $taken, 3, 0, 0];
+ push(@{$block}, $br);
+ $last_block_num = $block_num;
+ }
+ push(@blocks, $block) if (scalar(@{$block}) > 0);
+
+ # Add braces to first and last branch in group
+ foreach $block (@blocks) {
+ $block->[0]->[$BR_OPEN] = 1;
+ $block->[0]->[$BR_LEN]++;
+ $block->[scalar(@{$block}) - 1]->[$BR_CLOSE] = 1;
+ $block->[scalar(@{$block}) - 1]->[$BR_LEN]++;
+ }
+
+ return @blocks;
+}
+
+#
+# get_block_len(block)
+#
+# Calculate total text length of all branches in a block of branches.
+#
+
+sub get_block_len($)
+{
+ my ($block) = @_;
+ my $len = 0;
+ my $branch;
+
+ foreach $branch (@{$block}) {
+ $len += $branch->[$BR_LEN];
+ }
+
+ return $len;
+}
+
+
+#
+# get_branch_html(brdata)
+#
+# Return a list of HTML lines which represent the specified branch coverage
+# data in source code view.
+#
+
+sub get_branch_html($)
+{
+ my ($brdata) = @_;
+ my @blocks = get_branch_blocks($brdata);
+ my $block;
+ my $branch;
+ my $line_len = 0;
+ my $line = []; # [branch2|" ", branch|" ", ...]
+ my @lines; # [line1, line2, ...]
+ my @result;
+
+ # Distribute blocks to lines
+ foreach $block (@blocks) {
+ my $block_len = get_block_len($block);
+
+ # Does this block fit into the current line?
+ if ($line_len + $block_len <= $br_field_width) {
+ # Add it
+ $line_len += $block_len;
+ push(@{$line}, @{$block});
+ next;
+ } elsif ($block_len <= $br_field_width) {
+ # It would fit if the line was empty - add it to new
+ # line
+ push(@lines, $line);
+ $line_len = $block_len;
+ $line = [ @{$block} ];
+ next;
+ }
+ # Split the block into several lines
+ foreach $branch (@{$block}) {
+ if ($line_len + $branch->[$BR_LEN] >= $br_field_width) {
+ # Start a new line
+ if (($line_len + 1 <= $br_field_width) &&
+ scalar(@{$line}) > 0 &&
+ !$line->[scalar(@$line) - 1]->[$BR_CLOSE]) {
+ # Try to align branch symbols to be in
+ # one # row
+ push(@{$line}, " ");
+ }
+ push(@lines, $line);
+ $line_len = 0;
+ $line = [];
+ }
+ push(@{$line}, $branch);
+ $line_len += $branch->[$BR_LEN];
+ }
+ }
+ push(@lines, $line);
+
+ # Convert to HTML
+ foreach $line (@lines) {
+ my $current = "";
+ my $current_len = 0;
+
+ foreach $branch (@$line) {
+ # Skip alignment space
+ if ($branch eq " ") {
+ $current .= " ";
+ $current_len++;
+ next;
+ }
+
+ my ($block_num, $br_num, $taken, $len, $open, $close) =
+ @{$branch};
+ my $class;
+ my $title;
+ my $text;
+
+ if ($taken eq '-') {
+ $class = "branchNoExec";
+ $text = " # ";
+ $title = "Branch $br_num was not executed";
+ } elsif ($taken == 0) {
+ $class = "branchNoCov";
+ $text = " - ";
+ $title = "Branch $br_num was not taken";
+ } else {
+ $class = "branchCov";
+ $text = " + ";
+ $title = "Branch $br_num was taken $taken ".
+ "time";
+ $title .= "s" if ($taken > 1);
+ }
+ $current .= "[" if ($open);
+ $current .= "<span class=\"$class\" title=\"$title\">";
+ $current .= $text."</span>";
+ $current .= "]" if ($close);
+ $current_len += $len;
+ }
+
+ # Right-align result text
+ if ($current_len < $br_field_width) {
+ $current = (" "x($br_field_width - $current_len)).
+ $current;
+ }
+ push(@result, $current);
+ }
+
+ return @result;
+}
+
+
+#
+# format_count(count, width)
+#
+# Return a right-aligned representation of count that fits in width characters.
+#
+
+sub format_count($$)
+{
+ my ($count, $width) = @_;
+ my $result;
+ my $exp;
+
+ $result = sprintf("%*.0f", $width, $count);
+ while (length($result) > $width) {
+ last if ($count < 10);
+ $exp++;
+ $count = int($count/10);
+ $result = sprintf("%*s", $width, ">$count*10^$exp");
+ }
+ return $result;
+}
+
+#
+# write_source_line(filehandle, line_num, source, hit_count, converted,
+# brdata, add_anchor)
#
# Write formatted source code line. Return a line in a format as needed
# by gen_png()
#
-sub write_source_line(*$$$$)
+sub write_source_line(*$$$$$$)
{
+ my ($handle, $line, $source, $count, $converted, $brdata,
+ $add_anchor) = @_;
my $source_format;
- my $count;
+ my $count_format;
my $result;
my $anchor_start = "";
my $anchor_end = "";
-
- if (!(defined$_[3]))
- {
+ my $count_field_width = $line_field_width - 1;
+ my @br_html;
+ my $html;
+
+ # Get branch HTML data for this line
+ @br_html = get_branch_html($brdata) if ($br_coverage);
+
+ if (!defined($count)) {
$result = "";
$source_format = "";
- $count = " "x15;
- }
- elsif ($_[3] == 0)
- {
- $result = $_[3];
+ $count_format = " "x$count_field_width;
+ }
+ elsif ($count == 0) {
+ $result = $count;
$source_format = '<span class="lineNoCov">';
- $count = sprintf("%15d", $_[3]);
- }
- elsif ($_[4] && defined($highlight))
- {
- $result = "*".$_[3];
+ $count_format = format_count($count, $count_field_width);
+ }
+ elsif ($converted && defined($highlight)) {
+ $result = "*".$count;
$source_format = '<span class="lineDiffCov">';
- $count = sprintf("%15d", $_[3]);
- }
- else
- {
- $result = $_[3];
+ $count_format = format_count($count, $count_field_width);
+ }
+ else {
+ $result = $count;
$source_format = '<span class="lineCov">';
- $count = sprintf("%15d", $_[3]);
- }
-
- $result .= ":".$_[2];
+ $count_format = format_count($count, $count_field_width);
+ }
+ $result .= ":".$source;
# Write out a line number navigation anchor every $nav_resolution
# lines if necessary
- if ($frames && (($_[1] - 1) % $nav_resolution == 0))
+ if ($add_anchor)
{
$anchor_start = "<a name=\"$_[1]\">";
$anchor_end = "</a>";
@@ -2364,13 +3909,23 @@
# *************************************************************
- write_html($_[0],
- $anchor_start.
- '<span class="lineNum">'.sprintf("%8d", $_[1]).
- " </span>$source_format$count : ".
- escape_html($_[2]).($source_format?"</span>":"").
- $anchor_end."\n");
-
+ $html = $anchor_start;
+ $html .= "<span class=\"lineNum\">".sprintf("%8d", $line)." </span>";
+ $html .= shift(@br_html).":" if ($br_coverage);
+ $html .= "$source_format$count_format : ";
+ $html .= escape_html($source);
+ $html .= "</span>" if ($source_format);
+ $html .= $anchor_end."\n";
+
+ write_html($handle, $html);
+
+ if ($br_coverage) {
+ # Add lines for overlong branch information
+ foreach (@br_html) {
+ write_html($handle, "<span class=\"lineNum\">".
+ " </span>$_\n");
+ }
+ }
# *************************************************************
return($result);
@@ -2411,7 +3966,9 @@
sub write_html_epilog(*$;$)
{
+ my $basedir = $_[1];
my $break_code = "";
+ my $epilog;
if (defined($_[2]))
{
@@ -2422,17 +3979,17 @@
write_html($_[0], <<END_OF_HTML)
<table width="100%" border=0 cellspacing=0 cellpadding=0>
- <tr><td class="ruler"><img src="$_[1]glass.png" width=3 height=3 alt=""></td></tr>
- <tr><td class="versionInfo">Generated by: <a href="$lcov_url"$break_code>$lcov_version</a></td></tr>
+ <tr><td class="ruler"><img src="$_[1]glass.png" width=3 height=3 alt=""></td></tr>
+ <tr><td class="versionInfo">Generated by: <a href="$lcov_url"$break_code>$lcov_version</a></td></tr>
</table>
<br>
-
- </body>
- </html>
END_OF_HTML
;
- # *************************************************************
+ $epilog = $html_epilog;
+ $epilog =~ s/\@basedir\@/$basedir/g;
+
+ write_html($_[0], $epilog);
}
@@ -2459,8 +4016,8 @@
</head>
<frameset cols="$frame_width,*">
- <frame src="$_[2].gcov.overview.html" name="overview">
- <frame src="$_[2].gcov.html" name="source">
+ <frame src="$_[2].gcov.overview.$html_ext" name="overview">
+ <frame src="$_[2].gcov.$html_ext" name="source">
<noframes>
<center>Frames not supported by your browser!<br></center>
</noframes>
@@ -2488,7 +4045,7 @@
# *************************************************************
write_html($_[0], <<END_OF_HTML)
- <area shape="rect" coords="0,$y1,$x2,$y2" href="$_[1].gcov.html#$_[3]" target="source" alt="overview">
+ <area shape="rect" coords="0,$y1,$x2,$y2" href="$_[1].gcov.$html_ext#$_[3]" target="source" alt="overview">
END_OF_HTML
;
@@ -2551,7 +4108,7 @@
</map>
<center>
- <a href="$_[2].gcov.html#top" target="source">Top</a><br><br>
+ <a href="$_[2].gcov.$html_ext#top" target="source">Top</a><br><br>
<img src="$_[2].gcov.png" width=$overview_width height=$max_line alt="Overview" border=0 usemap="#overview">
</center>
</body>
@@ -2563,16 +4120,36 @@
}
+# format_rate(found, hit)
+#
+# Return formatted percent string for coverage rate.
+#
+
+sub format_rate($$)
+{
+ return $_[0] == 0 ? "-" : sprintf("%.1f", $_[1] * 100 / $_[0])." %";
+}
+
+
+sub max($$)
+{
+ my ($a, $b) = @_;
+
+ return $a if ($a > $b);
+ return $b;
+}
+
+
#
# write_header(filehandle, type, trunc_file_name, rel_file_name, lines_found,
-# lines_hit)
-#
-# Write a complete standard page header. TYPE may be (0, 1, 2, 3)
+# lines_hit, funcs_found, funcs_hit, sort_type)
+#
+# Write a complete standard page header. TYPE may be (0, 1, 2, 3, 4)
# corresponding to (directory view header, file view header, source view
-# header, test case description header)
-#
-
-sub write_header(*$$$$$)
+# header, test case description header, function view header)
+#
+
+sub write_header(*$$$$$$$$$$)
{
local *HTML_HANDLE = $_[0];
my $type = $_[1];
@@ -2580,68 +4157,77 @@
my $rel_filename = $_[3];
my $lines_found = $_[4];
my $lines_hit = $_[5];
+ my $fn_found = $_[6];
+ my $fn_hit = $_[7];
+ my $br_found = $_[8];
+ my $br_hit = $_[9];
+ my $sort_type = $_[10];
my $base_dir;
my $view;
my $test;
+ my $base_name;
+ my $style;
my $rate;
- my $base_name;
-
- # Calculate coverage rate
- if ($lines_found>0)
- {
- $rate = sprintf("%.1f", $lines_hit * 100 / $lines_found)." %";
- }
- else
- {
- $rate = "-";
- }
+ my @row_left;
+ my @row_right;
+ my $num_rows;
+ my $i;
$base_name = basename($rel_filename);
# Prepare text for "current view" field
- if ($type == 0)
+ if ($type == $HDR_DIR)
{
# Main overview
$base_dir = "";
$view = $overview_title;
}
- elsif ($type == 1)
+ elsif ($type == $HDR_FILE)
{
# Directory overview
$base_dir = get_relative_base_path($rel_filename);
- $view = "<a href=\"$base_dir"."index.html\">".
+ $view = "<a href=\"$base_dir"."index.$html_ext\">".
"$overview_title</a> - $trunc_name";
}
- elsif ($type == 2)
+ elsif ($type == $HDR_SOURCE || $type == $HDR_FUNC)
{
# File view
my $dir_name = dirname($rel_filename);
-
-
$base_dir = get_relative_base_path($dir_name);
if ($frames)
{
# Need to break frameset when clicking any of these
# links
- $view = "<a href=\"$base_dir"."index.html\" ".
+ $view = "<a href=\"$base_dir"."index.$html_ext\" ".
"target=\"_parent\">$overview_title</a> - ".
- "<a href=\"index.html\" target=\"_parent\">".
+ "<a href=\"index.$html_ext\" target=\"_parent\">".
"$dir_name</a> - $base_name";
}
else
{
- $view = "<a href=\"$base_dir"."index.html\">".
+ $view = "<a href=\"$base_dir"."index.$html_ext\">".
"$overview_title</a> - ".
- "<a href=\"index.html\">".
+ "<a href=\"index.$html_ext\">".
"$dir_name</a> - $base_name";
}
- }
- elsif ($type == 3)
+
+ # Add function suffix
+ if ($func_coverage) {
+ $view .= "<span style=\"font-size: 80%;\">";
+ if ($type == $HDR_SOURCE) {
+ $view .= " (source / <a href=\"$base_name.func.$html_ext\">functions</a>)";
+ } elsif ($type == $HDR_FUNC) {
+ $view .= " (<a href=\"$base_name.gcov.$html_ext\">source</a> / functions)";
+ }
+ $view .= "</span>";
+ }
+ }
+ elsif ($type == $HDR_TESTDESC)
{
# Test description header
$base_dir = "";
- $view = "<a href=\"$base_dir"."index.html\">".
+ $view = "<a href=\"$base_dir"."index.$html_ext\">".
"$overview_title</a> - test case descriptions";
}
@@ -2649,60 +4235,265 @@
$test = escape_html($test_title);
# Append link to test description page if available
- if (%test_description && ($type != 3))
+ if (%test_description && ($type != $HDR_TESTDESC))
{
- if ($frames && ($type == 2))
+ if ($frames && ($type == $HDR_SOURCE || $type == $HDR_FUNC))
{
# Need to break frameset when clicking this link
- $test .= " ( <a href=\"$base_dir".
- "descriptions.html\" target=\"_parent\">".
- "view test case descriptions</a> )";
+ $test .= " ( <span style=\"font-size:80%;\">".
+ "<a href=\"$base_dir".
+ "descriptions.$html_ext\" target=\"_parent\">".
+ "view descriptions</a></span> )";
}
else
{
- $test .= " ( <a href=\"$base_dir".
- "descriptions.html\">".
- "view test case descriptions</a> )";
+ $test .= " ( <span style=\"font-size:80%;\">".
+ "<a href=\"$base_dir".
+ "descriptions.$html_ext\">".
+ "view descriptions</a></span> )";
}
}
# Write header
write_header_prolog(*HTML_HANDLE, $base_dir);
- write_header_line(*HTML_HANDLE, "Current view", $view);
- write_header_line(*HTML_HANDLE, "Test", $test);
- write_header_line(*HTML_HANDLE, "Date", $date,
- "Instrumented lines", $lines_found);
- write_header_line(*HTML_HANDLE, "Code covered", $rate,
- "Executed lines", $lines_hit);
+
+ # Left row
+ push(@row_left, [[ "10%", "headerItem", "Current view:" ],
+ [ "35%", "headerValue", $view ]]);
+ push(@row_left, [[undef, "headerItem", "Test:"],
+ [undef, "headerValue", $test]]);
+ push(@row_left, [[undef, "headerItem", "Date:"],
+ [undef, "headerValue", $date]]);
+
+ # Right row
+ if ($legend && ($type == $HDR_SOURCE || $type == $HDR_FUNC)) {
+ my $text = <<END_OF_HTML;
+ Lines:
+ <span class="coverLegendCov">hit</span>
+ <span class="coverLegendNoCov">not hit</span>
+END_OF_HTML
+ if ($br_coverage) {
+ $text .= <<END_OF_HTML;
+ | Branches:
+ <span class="coverLegendCov">+</span> taken
+ <span class="coverLegendNoCov">-</span> not taken
+ <span class="coverLegendNoCov">#</span> not executed
+END_OF_HTML
+ }
+ push(@row_left, [[undef, "headerItem", "Legend:"],
+ [undef, "headerValueLeg", $text]]);
+ } elsif ($legend && ($type != $HDR_TESTDESC)) {
+ my $text = <<END_OF_HTML;
+ Rating:
+ <span class="coverLegendCovLo" title="Coverage rates below $med_limit % are classified as low">low: < $med_limit %</span>
+ <span class="coverLegendCovMed" title="Coverage rates between $med_limit % and $hi_limit % are classified as medium">medium: >= $med_limit %</span>
+ <span class="coverLegendCovHi" title="Coverage rates of $hi_limit % and more are classified as high">high: >= $hi_limit %</span>
+END_OF_HTML
+ push(@row_left, [[undef, "headerItem", "Legend:"],
+ [undef, "headerValueLeg", $text]]);
+ }
+ if ($type == $HDR_TESTDESC) {
+ push(@row_right, [[ "55%" ]]);
+ } else {
+ push(@row_right, [["15%", undef, undef ],
+ ["10%", "headerCovTableHead", "Hit" ],
+ ["10%", "headerCovTableHead", "Total" ],
+ ["15%", "headerCovTableHead", "Coverage"]]);
+ }
+ # Line coverage
+ $style = $rate_name[classify_rate($lines_found, $lines_hit,
+ $med_limit, $hi_limit)];
+ $rate = format_rate($lines_found, $lines_hit);
+ push(@row_right, [[undef, "headerItem", "Lines:"],
+ [undef, "headerCovTableEntry", $lines_hit],
+ [undef, "headerCovTableEntry", $lines_found],
+ [undef, "headerCovTableEntry$style", $rate]])
+ if ($type != $HDR_TESTDESC);
+ # Function coverage
+ if ($func_coverage) {
+ $style = $rate_name[classify_rate($fn_found, $fn_hit,
+ $fn_med_limit, $fn_hi_limit)];
+ $rate = format_rate($fn_found, $fn_hit);
+ push(@row_right, [[undef, "headerItem", "Functions:"],
+ [undef, "headerCovTableEntry", $fn_hit],
+ [undef, "headerCovTableEntry", $fn_found],
+ [undef, "headerCovTableEntry$style", $rate]])
+ if ($type != $HDR_TESTDESC);
+ }
+ # Branch coverage
+ if ($br_coverage) {
+ $style = $rate_name[classify_rate($br_found, $br_hit,
+ $br_med_limit, $br_hi_limit)];
+ $rate = format_rate($br_found, $br_hit);
+ push(@row_right, [[undef, "headerItem", "Branches:"],
+ [undef, "headerCovTableEntry", $br_hit],
+ [undef, "headerCovTableEntry", $br_found],
+ [undef, "headerCovTableEntry$style", $rate]])
+ if ($type != $HDR_TESTDESC);
+ }
+
+ # Print rows
+ $num_rows = max(scalar(@row_left), scalar(@row_right));
+ for ($i = 0; $i < $num_rows; $i++) {
+ my $left = $row_left[$i];
+ my $right = $row_right[$i];
+
+ if (!defined($left)) {
+ $left = [[undef, undef, undef], [undef, undef, undef]];
+ }
+ if (!defined($right)) {
+ $right = [];
+ }
+ write_header_line(*HTML_HANDLE, @{$left},
+ [ $i == 0 ? "5%" : undef, undef, undef],
+ @{$right});
+ }
+
+ # Fourth line
write_header_epilog(*HTML_HANDLE, $base_dir);
}
#
-# split_filename(filename)
-#
-# Return (path, filename, extension) for a given FILENAME.
-#
-
-sub split_filename($)
+# get_sorted_keys(hash_ref, sort_type)
+#
+
+sub get_sorted_keys($$)
+{
+ my ($hash, $type) = @_;
+
+ if ($type == $SORT_FILE) {
+ # Sort by name
+ return sort(keys(%{$hash}));
+ } elsif ($type == $SORT_LINE) {
+ # Sort by line coverage
+ return sort({$hash->{$a}[7] <=> $hash->{$b}[7]} keys(%{$hash}));
+ } elsif ($type == $SORT_FUNC) {
+ # Sort by function coverage;
+ return sort({$hash->{$a}[8] <=> $hash->{$b}[8]} keys(%{$hash}));
+ } elsif ($type == $SORT_BRANCH) {
+ # Sort by br coverage;
+ return sort({$hash->{$a}[9] <=> $hash->{$b}[9]} keys(%{$hash}));
+ }
+}
+
+sub get_sort_code($$$)
+{
+ my ($link, $alt, $base) = @_;
+ my $png;
+ my $link_start;
+ my $link_end;
+
+ if (!defined($link)) {
+ $png = "glass.png";
+ $link_start = "";
+ $link_end = "";
+ } else {
+ $png = "updown.png";
+ $link_start = '<a href="'.$link.'">';
+ $link_end = "</a>";
+ }
+
+ return ' <span class="tableHeadSort">'.$link_start.
+ '<img src="'.$base.$png.'" width=10 height=14 '.
+ 'alt="'.$alt.'" title="'.$alt.'" border=0>'.$link_end.'</span>';
+}
+
+sub get_file_code($$$$)
+{
+ my ($type, $text, $sort_button, $base) = @_;
+ my $result = $text;
+ my $link;
+
+ if ($sort_button) {
+ if ($type == $HEAD_NO_DETAIL) {
+ $link = "index.$html_ext";
+ } else {
+ $link = "index-detail.$html_ext";
+ }
+ }
+ $result .= get_sort_code($link, "Sort by name", $base);
+
+ return $result;
+}
+
+sub get_line_code($$$$$)
{
- if (!$_[0]) { return(); }
- my @path_components = split('/', $_[0]);
- my @file_components = split('\.', pop(@path_components));
- my $extension = pop(@file_components);
-
- return (join("/",@path_components), join(".",@file_components),
- $extension);
+ my ($type, $sort_type, $text, $sort_button, $base) = @_;
+ my $result = $text;
+ my $sort_link;
+
+ if ($type == $HEAD_NO_DETAIL) {
+ # Just text
+ if ($sort_button) {
+ $sort_link = "index-sort-l.$html_ext";
+ }
+ } elsif ($type == $HEAD_DETAIL_HIDDEN) {
+ # Text + link to detail view
+ $result .= ' ( <a class="detail" href="index-detail'.
+ $fileview_sortname[$sort_type].'.'.$html_ext.
+ '">show details</a> )';
+ if ($sort_button) {
+ $sort_link = "index-sort-l.$html_ext";
+ }
+ } else {
+ # Text + link to standard view
+ $result .= ' ( <a class="detail" href="index'.
+ $fileview_sortname[$sort_type].'.'.$html_ext.
+ '">hide details</a> )';
+ if ($sort_button) {
+ $sort_link = "index-detail-sort-l.$html_ext";
+ }
+ }
+ # Add sort button
+ $result .= get_sort_code($sort_link, "Sort by line coverage", $base);
+
+ return $result;
}
-
-#
-# write_file_table(filehandle, base_dir, overview, testhash, fileview)
+sub get_func_code($$$$)
+{
+ my ($type, $text, $sort_button, $base) = @_;
+ my $result = $text;
+ my $link;
+
+ if ($sort_button) {
+ if ($type == $HEAD_NO_DETAIL) {
+ $link = "index-sort-f.$html_ext";
+ } else {
+ $link = "index-detail-sort-f.$html_ext";
+ }
+ }
+ $result .= get_sort_code($link, "Sort by function coverage", $base);
+ return $result;
+}
+
+sub get_br_code($$$$)
+{
+ my ($type, $text, $sort_button, $base) = @_;
+ my $result = $text;
+ my $link;
+
+ if ($sort_button) {
+ if ($type == $HEAD_NO_DETAIL) {
+ $link = "index-sort-b.$html_ext";
+ } else {
+ $link = "index-detail-sort-b.$html_ext";
+ }
+ }
+ $result .= get_sort_code($link, "Sort by branch coverage", $base);
+ return $result;
+}
+
+#
+# write_file_table(filehandle, base_dir, overview, testhash, testfnchash,
+# testbrhash, fileview, sort_type)
#
# Write a complete file table. OVERVIEW is a reference to a hash containing
# the following mapping:
#
-# filename -> "lines_found,lines_hit,page_link"
+# filename -> "lines_found,lines_hit,funcs_found,funcs_hit,page_link,
+# func_link"
#
# TESTHASH is a reference to the following hash:
#
@@ -2714,95 +4505,138 @@
# otherwise.
#
-sub write_file_table(*$$$$)
+sub write_file_table(*$$$$$$$)
{
local *HTML_HANDLE = $_[0];
my $base_dir = $_[1];
- my %overview = %{$_[2]};
- my %testhash = %{$_[3]};
- my $fileview = $_[4];
+ my $overview = $_[2];
+ my $testhash = $_[3];
+ my $testfnchash = $_[4];
+ my $testbrhash = $_[5];
+ my $fileview = $_[6];
+ my $sort_type = $_[7];
my $filename;
my $bar_graph;
my $hit;
my $found;
+ my $fn_found;
+ my $fn_hit;
+ my $br_found;
+ my $br_hit;
my $page_link;
my $testname;
my $testdata;
- my $testcount;
+ my $testfncdata;
+ my $testbrdata;
my %affecting_tests;
- my $coverage_heading = "Coverage";
-
- # Provide a link to details/non-detail list if this is directory
- # overview and we are supposed to create a detail view
+ my $line_code = "";
+ my $func_code;
+ my $br_code;
+ my $file_code;
+ my @head_columns;
+
+ # Determine HTML code for column headings
if (($base_dir ne "") && $show_details)
{
- if (%testhash)
- {
- # This is the detail list, provide link to standard
- # list
- $coverage_heading .= " ( <a class=\"detail\" href=\"".
- "index.html\">hide ".
- "details</a> )";
- }
- else
- {
- # This is the standard list, provide link to detail
- # list
- $coverage_heading .= " ( <a class=\"detail\" href=\"".
- "index-detail.html\">show ".
- "details</a> )";
+ my $detailed = keys(%{$testhash});
+
+ $file_code = get_file_code($detailed ? $HEAD_DETAIL_HIDDEN :
+ $HEAD_NO_DETAIL,
+ $fileview ? "Filename" : "Directory",
+ $sort && $sort_type != $SORT_FILE,
+ $base_dir);
+ $line_code = get_line_code($detailed ? $HEAD_DETAIL_SHOWN :
+ $HEAD_DETAIL_HIDDEN,
+ $sort_type,
+ "Line Coverage",
+ $sort && $sort_type != $SORT_LINE,
+ $base_dir);
+ $func_code = get_func_code($detailed ? $HEAD_DETAIL_HIDDEN :
+ $HEAD_NO_DETAIL,
+ "Functions",
+ $sort && $sort_type != $SORT_FUNC,
+ $base_dir);
+ $br_code = get_br_code($detailed ? $HEAD_DETAIL_HIDDEN :
+ $HEAD_NO_DETAIL,
+ "Branches",
+ $sort && $sort_type != $SORT_BRANCH,
+ $base_dir);
+ } else {
+ $file_code = get_file_code($HEAD_NO_DETAIL,
+ $fileview ? "Filename" : "Directory",
+ $sort && $sort_type != $SORT_FILE,
+ $base_dir);
+ $line_code = get_line_code($HEAD_NO_DETAIL, $sort_type, "Line Coverage",
+ $sort && $sort_type != $SORT_LINE,
+ $base_dir);
+ $func_code = get_func_code($HEAD_NO_DETAIL, "Functions",
+ $sort && $sort_type != $SORT_FUNC,
+ $base_dir);
+ $br_code = get_br_code($HEAD_NO_DETAIL, "Branches",
+ $sort && $sort_type != $SORT_BRANCH,
+ $base_dir);
+ }
+ push(@head_columns, [ $line_code, 3 ]);
+ push(@head_columns, [ $func_code, 2]) if ($func_coverage);
+ push(@head_columns, [ $br_code, 2]) if ($br_coverage);
+
+ write_file_table_prolog(*HTML_HANDLE, $file_code, @head_columns);
+
+ foreach $filename (get_sorted_keys($overview, $sort_type))
+ {
+ my @columns;
+ ($found, $hit, $fn_found, $fn_hit, $br_found, $br_hit,
+ $page_link) = @{$overview->{$filename}};
+
+ # Line coverage
+ push(@columns, [$found, $hit, $med_limit, $hi_limit, 1]);
+ # Function coverage
+ if ($func_coverage) {
+ push(@columns, [$fn_found, $fn_hit, $fn_med_limit,
+ $fn_hi_limit, 0]);
}
- }
-
- write_file_table_prolog(*HTML_HANDLE,
- $fileview ? "Filename" : "Directory name",
- $coverage_heading);
-
- foreach $filename (sort(keys(%overview)))
- {
- ($found, $hit, $page_link) = split(",", $overview{$filename});
- $bar_graph = get_bar_graph_code($base_dir, $found, $hit);
-
- $testdata = $testhash{$filename};
-
- # Add anchor tag in case a page link is provided
- if ($page_link)
- {
- $filename = "<a href=\"$page_link\">$filename</a>";
+ # Branch coverage
+ if ($br_coverage) {
+ push(@columns, [$br_found, $br_hit, $br_med_limit,
+ $br_hi_limit, 0]);
}
-
- write_file_table_entry(*HTML_HANDLE, $filename, $bar_graph,
- $found, $hit);
+ write_file_table_entry(*HTML_HANDLE, $base_dir, $filename,
+ $page_link, @columns);
+
+ $testdata = $testhash->{$filename};
+ $testfncdata = $testfnchash->{$filename};
+ $testbrdata = $testbrhash->{$filename};
# Check whether we should write test specific coverage
# as well
if (!($show_details && $testdata)) { next; }
# Filter out those tests that actually affect this file
- %affecting_tests = %{ get_affecting_tests($testdata) };
+ %affecting_tests = %{ get_affecting_tests($testdata,
+ $testfncdata, $testbrdata) };
# Does any of the tests affect this file at all?
if (!%affecting_tests) { next; }
- # Write test details for this entry
- write_file_table_detail_heading(*HTML_HANDLE, "Test name",
- "Lines hit");
-
foreach $testname (keys(%affecting_tests))
{
- ($found, $hit) =
+ my @results;
+ ($found, $hit, $fn_found, $fn_hit, $br_found, $br_hit) =
split(",", $affecting_tests{$testname});
# Insert link to description of available
if ($test_description{$testname})
{
$testname = "<a href=\"$base_dir".
- "descriptions.html#$testname\">".
+ "descriptions.$html_ext#$testname\">".
"$testname</a>";
}
+ push(@results, [$found, $hit]);
+ push(@results, [$fn_found, $fn_hit]) if ($func_coverage);
+ push(@results, [$br_found, $br_hit]) if ($br_coverage);
write_file_table_detail_entry(*HTML_HANDLE, $testname,
- $found, $hit);
+ @results);
}
}
@@ -2839,33 +4673,248 @@
#
-# get_affecting_tests(hashref)
+# get_func_found_and_hit(sumfnccount)
+#
+# Return (f_found, f_hit) for sumfnccount
+#
+
+sub get_func_found_and_hit($)
+{
+ my ($sumfnccount) = @_;
+ my $function;
+ my $fn_found;
+ my $fn_hit;
+
+ $fn_found = scalar(keys(%{$sumfnccount}));
+ $fn_hit = 0;
+ foreach $function (keys(%{$sumfnccount})) {
+ if ($sumfnccount->{$function} > 0) {
+ $fn_hit++;
+ }
+ }
+ return ($fn_found, $fn_hit);
+}
+
+
+#
+# br_taken_to_num(taken)
+#
+# Convert a branch taken value .info format to number format.
+#
+
+sub br_taken_to_num($)
+{
+ my ($taken) = @_;
+
+ return 0 if ($taken eq '-');
+ return $taken + 1;
+}
+
+
+#
+# br_num_to_taken(taken)
+#
+# Convert a branch taken value in number format to .info format.
+#
+
+sub br_num_to_taken($)
+{
+ my ($taken) = @_;
+
+ return '-' if ($taken == 0);
+ return $taken - 1;
+}
+
+
+#
+# br_taken_add(taken1, taken2)
+#
+# Return the result of taken1 + taken2 for 'branch taken' values.
+#
+
+sub br_taken_add($$)
+{
+ my ($t1, $t2) = @_;
+
+ return $t1 if (!defined($t2));
+ return $t2 if (!defined($t1));
+ return $t1 if ($t2 eq '-');
+ return $t2 if ($t1 eq '-');
+ return $t1 + $t2;
+}
+
+
+#
+# br_taken_sub(taken1, taken2)
+#
+# Return the result of taken1 - taken2 for 'branch taken' values. Return 0
+# if the result would become negative.
+#
+
+sub br_taken_sub($$)
+{
+ my ($t1, $t2) = @_;
+
+ return $t1 if (!defined($t2));
+ return undef if (!defined($t1));
+ return $t1 if ($t1 eq '-');
+ return $t1 if ($t2 eq '-');
+ return 0 if $t2 > $t1;
+ return $t1 - $t2;
+}
+
+
+#
+# br_ivec_len(vector)
+#
+# Return the number of entries in the branch coverage vector.
+#
+
+sub br_ivec_len($)
+{
+ my ($vec) = @_;
+
+ return 0 if (!defined($vec));
+ return (length($vec) * 8 / $BR_VEC_WIDTH) / $BR_VEC_ENTRIES;
+}
+
+
+#
+# br_ivec_get(vector, number)
+#
+# Return an entry from the branch coverage vector.
+#
+
+sub br_ivec_get($$)
+{
+ my ($vec, $num) = @_;
+ my $block;
+ my $branch;
+ my $taken;
+ my $offset = $num * $BR_VEC_ENTRIES;
+
+ # Retrieve data from vector
+ $block = vec($vec, $offset + $BR_BLOCK, $BR_VEC_WIDTH);
+ $branch = vec($vec, $offset + $BR_BRANCH, $BR_VEC_WIDTH);
+ $taken = vec($vec, $offset + $BR_TAKEN, $BR_VEC_WIDTH);
+
+ # Decode taken value from an integer
+ $taken = br_num_to_taken($taken);
+
+ return ($block, $branch, $taken);
+}
+
+
+#
+# br_ivec_push(vector, block, branch, taken)
+#
+# Add an entry to the branch coverage vector. If an entry with the same
+# branch ID already exists, add the corresponding taken values.
+#
+
+sub br_ivec_push($$$$)
+{
+ my ($vec, $block, $branch, $taken) = @_;
+ my $offset;
+ my $num = br_ivec_len($vec);
+ my $i;
+
+ $vec = "" if (!defined($vec));
+
+ # Check if branch already exists in vector
+ for ($i = 0; $i < $num; $i++) {
+ my ($v_block, $v_branch, $v_taken) = br_ivec_get($vec, $i);
+
+ next if ($v_block != $block || $v_branch != $branch);
+
+ # Add taken counts
+ $taken = br_taken_add($taken, $v_taken);
+ last;
+ }
+
+ $offset = $i * $BR_VEC_ENTRIES;
+ $taken = br_taken_to_num($taken);
+
+ # Add to vector
+ vec($vec, $offset + $BR_BLOCK, $BR_VEC_WIDTH) = $block;
+ vec($vec, $offset + $BR_BRANCH, $BR_VEC_WIDTH) = $branch;
+ vec($vec, $offset + $BR_TAKEN, $BR_VEC_WIDTH) = $taken;
+
+ return $vec;
+}
+
+
+#
+# get_br_found_and_hit(sumbrcount)
+#
+# Return (br_found, br_hit) for sumbrcount
+#
+
+sub get_br_found_and_hit($)
+{
+ my ($sumbrcount) = @_;
+ my $line;
+ my $br_found = 0;
+ my $br_hit = 0;
+
+ foreach $line (keys(%{$sumbrcount})) {
+ my $brdata = $sumbrcount->{$line};
+ my $i;
+ my $num = br_ivec_len($brdata);
+
+ for ($i = 0; $i < $num; $i++) {
+ my $taken;
+
+ (undef, undef, $taken) = br_ivec_get($brdata, $i);
+
+ $br_found++;
+ $br_hit++ if ($taken ne "-" && $taken > 0);
+ }
+ }
+
+ return ($br_found, $br_hit);
+}
+
+
+#
+# get_affecting_tests(testdata, testfncdata, testbrdata)
#
# HASHREF contains a mapping filename -> (linenumber -> exec count). Return
# a hash containing mapping filename -> "lines found, lines hit" for each
# filename which has a nonzero hit count.
#
-sub get_affecting_tests($)
+sub get_affecting_tests($$$)
{
- my %hash = %{$_[0]};
+ my ($testdata, $testfncdata, $testbrdata) = @_;
my $testname;
my $testcount;
+ my $testfnccount;
+ my $testbrcount;
my %result;
my $found;
my $hit;
-
- foreach $testname (keys(%hash))
+ my $fn_found;
+ my $fn_hit;
+ my $br_found;
+ my $br_hit;
+
+ foreach $testname (keys(%{$testdata}))
{
# Get (line number -> count) hash for this test case
- $testcount = $hash{$testname};
+ $testcount = $testdata->{$testname};
+ $testfnccount = $testfncdata->{$testname};
+ $testbrcount = $testbrdata->{$testname};
# Calculate sum
($found, $hit) = get_found_and_hit($testcount);
+ ($fn_found, $fn_hit) = get_func_found_and_hit($testfnccount);
+ ($br_found, $br_hit) = get_br_found_and_hit($testbrcount);
if ($hit>0)
{
- $result{$testname} = "$found,$hit";
+ $result{$testname} = "$found,$hit,$fn_found,$fn_hit,".
+ "$br_found,$br_hit";
}
}
@@ -2873,9 +4922,21 @@
}
+sub get_hash_reverse($)
+{
+ my ($hash) = @_;
+ my %result;
+
+ foreach (keys(%{$hash})) {
+ $result{$hash->{$_}} = $_;
+ }
+
+ return \%result;
+}
+
#
# write_source(filehandle, source_filename, count_data, checksum_data,
-# converted_data)
+# converted_data, func_data, sumbrcount)
#
# Write an HTML view of a source code file. Returns a list containing
# data as needed by gen_png().
@@ -2883,7 +4944,7 @@
# Die on error.
#
-sub write_source($$$$$)
+sub write_source($$$$$$$)
{
local *HTML_HANDLE = $_[0];
local *SOURCE_HANDLE;
@@ -2893,6 +4954,10 @@
my @result;
my $checkdata = $_[3];
my $converted = $_[4];
+ my $funcdata = $_[5];
+ my $sumbrcount = $_[6];
+ my $datafunc = get_hash_reverse($funcdata);
+ my $add_anchor;
if ($_[2])
{
@@ -2908,6 +4973,9 @@
{
chomp($_);
+ # Also remove CR from line-end
+ s/\015$//;
+
# Source code matches coverage data?
if (defined($checkdata->{$line_number}) &&
($checkdata->{$line_number} ne md5_base64($_)))
@@ -2916,10 +4984,25 @@
"$line_number\n");
}
+ $add_anchor = 0;
+ if ($frames) {
+ if (($line_number - 1) % $nav_resolution == 0) {
+ $add_anchor = 1;
+ }
+ }
+ if ($func_coverage) {
+ if ($line_number == 1) {
+ $add_anchor = 1;
+ } elsif (defined($datafunc->{$line_number +
+ $func_offset})) {
+ $add_anchor = 1;
+ }
+ }
push (@result,
write_source_line(HTML_HANDLE, $line_number,
$_, $count_data{$line_number},
- $converted->{$line_number}));
+ $converted->{$line_number},
+ $sumbrcount->{$line_number}, $add_anchor));
}
close(SOURCE_HANDLE);
@@ -2928,6 +5011,141 @@
}
+sub funcview_get_func_code($$$)
+{
+ my ($name, $base, $type) = @_;
+ my $result;
+ my $link;
+
+ if ($sort && $type == 1) {
+ $link = "$name.func.$html_ext";
+ }
+ $result = "Function Name";
+ $result .= get_sort_code($link, "Sort by function name", $base);
+
+ return $result;
+}
+
+sub funcview_get_count_code($$$)
+{
+ my ($name, $base, $type) = @_;
+ my $result;
+ my $link;
+
+ if ($sort && $type == 0) {
+ $link = "$name.func-sort-c.$html_ext";
+ }
+ $result = "Hit count";
+ $result .= get_sort_code($link, "Sort by hit count", $base);
+
+ return $result;
+}
+
+#
+# funcview_get_sorted(funcdata, sumfncdata, sort_type)
+#
+# Depending on the value of sort_type, return a list of functions sorted
+# by name (type 0) or by the associated call count (type 1).
+#
+
+sub funcview_get_sorted($$$)
+{
+ my ($funcdata, $sumfncdata, $type) = @_;
+
+ if ($type == 0) {
+ return sort(keys(%{$funcdata}));
+ }
+ return sort({$sumfncdata->{$b} <=> $sumfncdata->{$a}}
+ keys(%{$sumfncdata}));
+}
+
+#
+# write_function_table(filehandle, source_file, sumcount, funcdata,
+# sumfnccount, testfncdata, sumbrcount, testbrdata,
+# base_name, base_dir, sort_type)
+#
+# Write an HTML table listing all functions in a source file, including
+# also function call counts and line coverages inside of each function.
+#
+# Die on error.
+#
+
+sub write_function_table(*$$$$$$$$$$)
+{
+ local *HTML_HANDLE = $_[0];
+ my $source = $_[1];
+ my $sumcount = $_[2];
+ my $funcdata = $_[3];
+ my $sumfncdata = $_[4];
+ my $testfncdata = $_[5];
+ my $sumbrcount = $_[6];
+ my $testbrdata = $_[7];
+ my $name = $_[8];
+ my $base = $_[9];
+ my $type = $_[10];
+ my $func;
+ my $func_code;
+ my $count_code;
+
+ # Get HTML code for headings
+ $func_code = funcview_get_func_code($name, $base, $type);
+ $count_code = funcview_get_count_code($name, $base, $type);
+ write_html(*HTML_HANDLE, <<END_OF_HTML)
+ <center>
+ <table width="60%" cellpadding=1 cellspacing=1 border=0>
+ <tr><td><br></td></tr>
+ <tr>
+ <td width="80%" class="tableHead">$func_code</td>
+ <td width="20%" class="tableHead">$count_code</td>
+ </tr>
+END_OF_HTML
+ ;
+
+ # Get a sorted table
+ foreach $func (funcview_get_sorted($funcdata, $sumfncdata, $type)) {
+ if (!defined($funcdata->{$func}))
+ {
+ next;
+ }
+
+ my $startline = $funcdata->{$func} - $func_offset;
+ my $name = $func;
+ my $count = $sumfncdata->{$name};
+ my $countstyle;
+
+ # Demangle C++ function names if requested
+ if ($demangle_cpp) {
+ $name = `c++filt "$name"`;
+ chomp($name);
+ }
+ # Escape any remaining special characters
+ $name = escape_html($name);
+ if ($startline < 1) {
+ $startline = 1;
+ }
+ if ($count == 0) {
+ $countstyle = "coverFnLo";
+ } else {
+ $countstyle = "coverFnHi";
+ }
+
+ write_html(*HTML_HANDLE, <<END_OF_HTML)
+ <tr>
+ <td class="coverFn"><a href="$source#$startline">$name</a></td>
+ <td class="$countstyle">$count</td>
+ </tr>
+END_OF_HTML
+ ;
+ }
+ write_html(*HTML_HANDLE, <<END_OF_HTML)
+ </table>
+ <br>
+ </center>
+END_OF_HTML
+ ;
+}
+
+
#
# info(printf_parameter)
#
@@ -2982,57 +5200,45 @@
#
-# add_counts(data1_ref, data2_ref)
-#
-# DATA1_REF and DATA2_REF are references to hashes containing a mapping
-#
-# line number -> execution count
-#
-# Return a list (RESULT_REF, LINES_FOUND, LINES_HIT) where RESULT_REF
-# is a reference to a hash containing the combined mapping in which
-# execution counts are added.
-#
-
-sub add_counts($$)
+# subtract_fnccounts(data, base)
+#
+# Subtract function call counts found in base from those in data.
+# Return (data, f_found, f_hit).
+#
+
+sub subtract_fnccounts($$)
{
- my %data1 = %{$_[0]}; # Hash 1
- my %data2 = %{$_[1]}; # Hash 2
- my %result; # Resulting hash
- my $line; # Current line iteration scalar
- my $data1_count; # Count of line in hash1
- my $data2_count; # Count of line in hash2
- my $found = 0; # Total number of lines found
- my $hit = 0; # Number of lines with a count > 0
-
- foreach $line (keys(%data1))
- {
- $data1_count = $data1{$line};
- $data2_count = $data2{$line};
-
- # Add counts if present in both hashes
- if (defined($data2_count)) { $data1_count += $data2_count; }
-
- # Store sum in %result
- $result{$line} = $data1_count;
-
- $found++;
- if ($data1_count > 0) { $hit++; }
- }
-
- # Add lines unique to data2
- foreach $line (keys(%data2))
- {
- # Skip lines already in data1
- if (defined($data1{$line})) { next; }
-
- # Copy count from data2
- $result{$line} = $data2{$line};
-
- $found++;
- if ($result{$line} > 0) { $hit++; }
- }
-
- return (\%result, $found, $hit);
+ my %data;
+ my %base;
+ my $func;
+ my $data_count;
+ my $base_count;
+ my $fn_hit = 0;
+ my $fn_found = 0;
+
+ %data = %{$_[0]} if (defined($_[0]));
+ %base = %{$_[1]} if (defined($_[1]));
+ foreach $func (keys(%data)) {
+ $fn_found++;
+ $data_count = $data{$func};
+ $base_count = $base{$func};
+
+ if (defined($base_count)) {
+ $data_count -= $base_count;
+
+ # Make sure we don't get negative numbers
+ if ($data_count < 0) {
+ $data_count = 0;
+ }
+ }
+
+ $data{$func} = $data_count;
+ if ($data_count > 0) {
+ $fn_hit++;
+ }
+ }
+
+ return (\%data, $fn_found, $fn_hit);
}
@@ -3053,14 +5259,25 @@
my $data_testdata;
my $data_funcdata;
my $data_checkdata;
+ my $data_testfncdata;
+ my $data_testbrdata;
my $data_count;
+ my $data_testfnccount;
+ my $data_testbrcount;
my $base;
- my $base_testdata;
my $base_checkdata;
+ my $base_sumfnccount;
+ my $base_sumbrcount;
my $base_count;
my $sumcount;
+ my $sumfnccount;
+ my $sumbrcount;
my $found;
my $hit;
+ my $fn_found;
+ my $fn_hit;
+ my $br_found;
+ my $br_hit;
foreach $filename (keys(%data_hash))
{
@@ -3068,50 +5285,80 @@
$data = $data_hash{$filename};
$base = $base_hash{$filename};
+ # Skip data entries for which no base entry exists
+ if (!defined($base))
+ {
+ next;
+ }
+
# Get set entries for data and baseline
- ($data_testdata, undef, $data_funcdata, $data_checkdata) =
+ ($data_testdata, undef, $data_funcdata, $data_checkdata,
+ $data_testfncdata, undef, $data_testbrdata) =
get_info_entry($data);
- ($base_testdata, $base_count, undef, $base_checkdata) =
+ (undef, $base_count, undef, $base_checkdata, undef,
+ $base_sumfnccount, undef, $base_sumbrcount) =
get_info_entry($base);
# Check for compatible checksums
merge_checksums($data_checkdata, $base_checkdata, $filename);
- # Sumcount has to be calculated anew
+ # sumcount has to be calculated anew
$sumcount = {};
+ $sumfnccount = {};
+ $sumbrcount = {};
# For each test case, subtract test specific counts
foreach $testname (keys(%{$data_testdata}))
{
# Get counts of both data and baseline
$data_count = $data_testdata->{$testname};
-
- $hit = 0;
+ $data_testfnccount = $data_testfncdata->{$testname};
+ $data_testbrcount = $data_testbrdata->{$testname};
($data_count, undef, $hit) =
subtract_counts($data_count, $base_count);
+ ($data_testfnccount) =
+ subtract_fnccounts($data_testfnccount,
+ $base_sumfnccount);
+ ($data_testbrcount) =
+ combine_brcount($data_testbrcount,
+ $base_sumbrcount, $BR_SUB);
+
# Check whether this test case did hit any line at all
if ($hit > 0)
{
# Write back resulting hash
$data_testdata->{$testname} = $data_count;
+ $data_testfncdata->{$testname} =
+ $data_testfnccount;
+ $data_testbrdata->{$testname} =
+ $data_testbrcount;
}
else
{
# Delete test case which did not impact this
# file
delete($data_testdata->{$testname});
+ delete($data_testfncdata->{$testname});
+ delete($data_testbrdata->{$testname});
}
# Add counts to sum of counts
($sumcount, $found, $hit) =
add_counts($sumcount, $data_count);
+ ($sumfnccount, $fn_found, $fn_hit) =
+ add_fnccount($sumfnccount, $data_testfnccount);
+ ($sumbrcount, $br_found, $br_hit) =
+ combine_brcount($sumbrcount, $data_testbrcount,
+ $BR_ADD);
}
# Write back resulting entry
- set_info_entry($data, $data_testdata, $sumcount,
- $data_funcdata, $data_checkdata, $found, $hit);
+ set_info_entry($data, $data_testdata, $sumcount, $data_funcdata,
+ $data_checkdata, $data_testfncdata, $sumfnccount,
+ $data_testbrdata, $sumbrcount, $found, $hit,
+ $fn_found, $fn_hit, $br_found, $br_hit);
$data_hash{$filename} = $data;
}
@@ -3165,179 +5412,6 @@
#
-# merge_checksums(ref1, ref2, filename)
-#
-# REF1 and REF2 are references to hashes containing a mapping
-#
-# line number -> checksum
-#
-# Merge checksum lists defined in REF1 and REF2 and return reference to
-# resulting hash. Die if a checksum for a line is defined in both hashes
-# but does not match.
-#
-
-sub merge_checksums($$$)
-{
- my $ref1 = $_[0];
- my $ref2 = $_[1];
- my $filename = $_[2];
- my %result;
- my $line;
-
- foreach $line (keys(%{$ref1}))
- {
- if (defined($ref2->{$line}) &&
- ($ref1->{$line} ne $ref2->{$line}))
- {
- die("ERROR: checksum mismatch at $filename:$line\n");
- }
- $result{$line} = $ref1->{$line};
- }
-
- foreach $line (keys(%{$ref2}))
- {
- $result{$line} = $ref2->{$line};
- }
-
- return \%result;
-}
-
-
-#
-# combine_info_entries(entry_ref1, entry_ref2, filename)
-#
-# Combine .info data entry hashes referenced by ENTRY_REF1 and ENTRY_REF2.
-# Return reference to resulting hash.
-#
-
-sub combine_info_entries($$$)
-{
- my $entry1 = $_[0]; # Reference to hash containing first entry
- my $testdata1;
- my $sumcount1;
- my $funcdata1;
- my $checkdata1;
-
- my $entry2 = $_[1]; # Reference to hash containing second entry
- my $testdata2;
- my $sumcount2;
- my $funcdata2;
- my $checkdata2;
-
- my %result; # Hash containing combined entry
- my %result_testdata;
- my $result_sumcount = {};
- my %result_funcdata;
- my $lines_found;
- my $lines_hit;
-
- my $testname;
- my $filename = $_[2];
-
- # Retrieve data
- ($testdata1, $sumcount1, $funcdata1, $checkdata1) =
- get_info_entry($entry1);
- ($testdata2, $sumcount2, $funcdata2, $checkdata2) =
- get_info_entry($entry2);
-
- # Merge checksums
- $checkdata1 = merge_checksums($checkdata1, $checkdata2, $filename);
-
- # Combine funcdata
- foreach (keys(%{$funcdata1}))
- {
- $result_funcdata{$_} = $funcdata1->{$_};
- }
-
- foreach (keys(%{$funcdata2}))
- {
- $result_funcdata{$_} = $funcdata2->{$_};
- }
-
- # Combine testdata
- foreach $testname (keys(%{$testdata1}))
- {
- if (defined($testdata2->{$testname}))
- {
- # testname is present in both entries, requires
- # combination
- ($result_testdata{$testname}) =
- add_counts($testdata1->{$testname},
- $testdata2->{$testname});
- }
- else
- {
- # testname only present in entry1, add to result
- $result_testdata{$testname} = $testdata1->{$testname};
- }
-
- # update sum count hash
- ($result_sumcount, $lines_found, $lines_hit) =
- add_counts($result_sumcount,
- $result_testdata{$testname});
- }
-
- foreach $testname (keys(%{$testdata2}))
- {
- # Skip testnames already covered by previous iteration
- if (defined($testdata1->{$testname})) { next; }
-
- # testname only present in entry2, add to result hash
- $result_testdata{$testname} = $testdata2->{$testname};
-
- # update sum count hash
- ($result_sumcount, $lines_found, $lines_hit) =
- add_counts($result_sumcount,
- $result_testdata{$testname});
- }
-
- # Calculate resulting sumcount
-
- # Store result
- set_info_entry(\%result, \%result_testdata, $result_sumcount,
- \%result_funcdata, $checkdata1, $lines_found,
- $lines_hit);
-
- return(\%result);
-}
-
-
-#
-# combine_info_files(info_ref1, info_ref2)
-#
-# Combine .info data in hashes referenced by INFO_REF1 and INFO_REF2. Return
-# reference to resulting hash.
-#
-
-sub combine_info_files($$)
-{
- my %hash1 = %{$_[0]};
- my %hash2 = %{$_[1]};
- my $filename;
-
- foreach $filename (keys(%hash2))
- {
- if ($hash1{$filename})
- {
- # Entry already exists in hash1, combine them
- $hash1{$filename} =
- combine_info_entries($hash1{$filename},
- $hash2{$filename},
- $filename);
- }
- else
- {
- # Entry is unique in both hashes, simply add to
- # resulting hash
- $hash1{$filename} = $hash2{$filename};
- }
- }
-
- return(\%hash1);
-}
-
-
-#
# apply_prefix(filename, prefix)
#
# If FILENAME begins with PREFIX, remove PREFIX from FILENAME and return
@@ -3387,7 +5461,7 @@
# Redirect to /dev/null
($mode & 1) && open(STDOUT, ">/dev/null");
($mode & 2) && open(STDERR, ">/dev/null");
-
+
system(@_);
$result = $?;
@@ -3398,7 +5472,7 @@
# Restore old handles
($mode & 1) && open(STDOUT, ">>&OLD_STDOUT");
($mode & 2) && open(STDERR, ">>&OLD_STDERR");
-
+
return $result;
}
@@ -3473,3 +5547,102 @@
}
}
}
+
+
+#
+# get_html_prolog(FILENAME)
+#
+# If FILENAME is defined, return contents of file. Otherwise return default
+# HTML prolog. Die on error.
+#
+
+sub get_html_prolog($)
+{
+ my $filename = $_[0];
+ my $result = "";
+
+ if (defined($filename))
+ {
+ local *HANDLE;
+
+ open(HANDLE, "<".$filename)
+ or die("ERROR: cannot open html prolog $filename!\n");
+ while (<HANDLE>)
+ {
+ $result .= $_;
+ }
+ close(HANDLE);
+ }
+ else
+ {
+ $result = <<END_OF_HTML
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+
+<html lang="en">
+
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>\@pagetitle\@</title>
+ <link rel="stylesheet" type="text/css" href="\@basedir\@gcov.css">
+</head>
+
+<body>
+
+END_OF_HTML
+ ;
+ }
+
+ return $result;
+}
+
+
+#
+# get_html_epilog(FILENAME)
+#
+# If FILENAME is defined, return contents of file. Otherwise return default
+# HTML epilog. Die on error.
+#
+sub get_html_epilog($)
+{
+ my $filename = $_[0];
+ my $result = "";
+
+ if (defined($filename))
+ {
+ local *HANDLE;
+
+ open(HANDLE, "<".$filename)
+ or die("ERROR: cannot open html epilog $filename!\n");
+ while (<HANDLE>)
+ {
+ $result .= $_;
+ }
+ close(HANDLE);
+ }
+ else
+ {
+ $result = <<END_OF_HTML
+
+</body>
+</html>
+END_OF_HTML
+ ;
+ }
+
+ return $result;
+
+}
+
+sub warn_handler($)
+{
+ my ($msg) = @_;
+
+ warn("$tool_name: $msg");
+}
+
+sub die_handler($)
+{
+ my ($msg) = @_;
+
+ die("$tool_name: $msg");
+}
--- a/utils/lcov/geninfo Sat Aug 20 14:41:19 2011 -0400
+++ b/utils/lcov/geninfo Mon Oct 17 16:59:17 2011 -0400
@@ -1,6 +1,6 @@
#!/usr/bin/perl -w
#
-# Copyright (c) International Business Machines Corp., 2002
+# Copyright (c) International Business Machines Corp., 2002,2010
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -44,18 +44,24 @@
# 2004-02-16 / Andreas Krebbel: Added support for .gcno/.gcda files and
# gcov versioning
# 2004-08-09 / Peter Oberparleiter: added configuration file support
+# 2008-07-14 / Tom Zoerner: added --function-coverage command line option
+# 2008-08-13 / Peter Oberparleiter: modified function coverage
+# implementation (now enabled per default)
#
use strict;
use File::Basename;
+use File::Spec::Functions qw /abs2rel catdir file_name_is_absolute splitdir
+ splitpath/;
use Getopt::Long;
use Digest::MD5 qw(md5_base64);
# Constants
-our $lcov_version = "LTP GCOV extension version 1.4";
+our $lcov_version = 'LCOV version 1.9';
our $lcov_url = "http://ltp.sourceforge.net/coverage/lcov.php";
our $gcov_tool = "gcov";
+our $tool_name = basename($0);
our $GCOV_VERSION_3_4_0 = 0x30400;
our $GCOV_VERSION_3_3_0 = 0x30300;
@@ -64,31 +70,79 @@
our $GCNO_FILE_MAGIC = 0x67636e6f;
our $BBG_FILE_MAGIC = 0x67626267;
-our $COMPAT_SLES9 = "sles9";
+our $COMPAT_HAMMER = "hammer";
+
+our $ERROR_GCOV = 0;
+our $ERROR_SOURCE = 1;
+our $ERROR_GRAPH = 2;
+
+our $EXCL_START = "LCOV_EXCL_START";
+our $EXCL_STOP = "LCOV_EXCL_STOP";
+our $EXCL_LINE = "LCOV_EXCL_LINE";
+
+our $BR_LINE = 0;
+our $BR_BLOCK = 1;
+our $BR_BRANCH = 2;
+our $BR_TAKEN = 3;
+our $BR_VEC_ENTRIES = 4;
+our $BR_VEC_WIDTH = 32;
+
+our $UNNAMED_BLOCK = 9999;
# Prototypes
sub print_usage(*);
sub gen_info($);
-sub process_dafile($);
+sub process_dafile($$);
sub match_filename($@);
sub solve_ambiguous_match($$$);
sub split_filename($);
sub solve_relative_path($$);
-sub get_dir($);
sub read_gcov_header($);
sub read_gcov_file($);
-sub read_bb_file($);
-sub read_string(*$);
-sub read_gcno_file($);
-sub read_gcno_string(*$);
-sub read_sles9_bbg_file($);
-sub read_sles9_bbg_string(*$);
-sub unpack_int32($$);
sub info(@);
sub get_gcov_version();
sub system_no_output($@);
sub read_config($);
sub apply_config($);
+sub get_exclusion_data($);
+sub apply_exclusion_data($$);
+sub process_graphfile($$);
+sub filter_fn_name($);
+sub warn_handler($);
+sub die_handler($);
+sub graph_error($$);
+sub graph_expect($);
+sub graph_read(*$;$);
+sub graph_skip(*$;$);
+sub sort_uniq(@);
+sub sort_uniq_lex(@);
+sub graph_cleanup($);
+sub graph_find_base($);
+sub graph_from_bb($$$);
+sub graph_add_order($$$);
+sub read_bb_word(*;$);
+sub read_bb_value(*;$);
+sub read_bb_string(*$);
+sub read_bb($$);
+sub read_bbg_word(*;$);
+sub read_bbg_value(*;$);
+sub read_bbg_string(*);
+sub read_bbg_lines_record(*$$$$$$);
+sub read_bbg($$);
+sub read_gcno_word(*;$);
+sub read_gcno_value(*$;$);
+sub read_gcno_string(*$);
+sub read_gcno_lines_record(*$$$$$$$);
+sub read_gcno_function_record(*$$$$);
+sub read_gcno($$);
+sub get_gcov_capabilities();
+sub get_overall_line($$$$);
+sub print_overall_rate($$$$$$$$$);
+sub br_gvec_len($);
+sub br_gvec_get($$);
+sub debug($);
+sub int_handler();
+
# Global variables
our $gcov_version;
@@ -96,18 +150,30 @@
our $data_file_extension;
our @data_directory;
our $test_name = "";
-our $source_dirs = "";
our $quiet;
our $help;
our $output_filename;
+our $base_directory;
our $version;
our $follow;
-our $nochecksum;
-our $preserve_paths;
-our $adjust_testname = (`uname -m` =~ /^s390/); # Always on on s390
+our $checksum;
+our $no_checksum;
+our $compat_libtool;
+our $no_compat_libtool;
+our $adjust_testname;
our $config; # Configuration file contents
our $compatibility; # Compatibility version flag - used to indicate
# non-standard GCOV data format versions
+our @ignore_errors; # List of errors to ignore (parameter)
+our @ignore; # List of errors to ignore (array)
+our $initial;
+our $no_recursion = 0;
+our $maxdepth;
+our $no_markers = 0;
+our $opt_derive_func_data = 0;
+our $debug = 0;
+our $gcov_caps;
+our @gcov_options;
our $cwd = `pwd`;
chomp($cwd);
@@ -119,9 +185,17 @@
# Register handler routine to be called when interrupted
$SIG{"INT"} = \&int_handler;
+$SIG{__WARN__} = \&warn_handler;
+$SIG{__DIE__} = \&die_handler;
+
+# Prettify version string
+$lcov_version =~ s/\$\s*Revision\s*:?\s*(\S+)\s*\$/$1/;
+
+# Set LANG so that gcov output will be in a unified format
+$ENV{"LANG"} = "C";
# Read configuration file if available
-if (-r $ENV{"HOME"}."/.lcovrc")
+if (defined($ENV{"HOME"}) && (-r $ENV{"HOME"}."/.lcovrc"))
{
$config = read_config($ENV{"HOME"}."/.lcovrc");
}
@@ -136,23 +210,57 @@
apply_config({
"geninfo_gcov_tool" => \$gcov_tool,
"geninfo_adjust_testname" => \$adjust_testname,
- "geninfo_no_checksum" => \$nochecksum});
+ "geninfo_checksum" => \$checksum,
+ "geninfo_no_checksum" => \$no_checksum, # deprecated
+ "geninfo_compat_libtool" => \$compat_libtool});
+
+ # Merge options
+ if (defined($no_checksum))
+ {
+ $checksum = ($no_checksum ? 0 : 1);
+ $no_checksum = undef;
+ }
}
# Parse command line options
-if (!GetOptions("test-name=s" => \$test_name,
- "output-filename=s" => \$output_filename,
- "source-dirs=s" => \$source_dirs,
- "no-checksum" => \$nochecksum,
- "version" =>\$version,
- "quiet" => \$quiet,
- "help" => \$help,
- "follow" => \$follow
+if (!GetOptions("test-name|t=s" => \$test_name,
+ "output-filename|o=s" => \$output_filename,
+ "checksum" => \$checksum,
+ "no-checksum" => \$no_checksum,
+ "base-directory|b=s" => \$base_directory,
+ "version|v" =>\$version,
+ "quiet|q" => \$quiet,
+ "help|h|?" => \$help,
+ "follow|f" => \$follow,
+ "compat-libtool" => \$compat_libtool,
+ "no-compat-libtool" => \$no_compat_libtool,
+ "gcov-tool=s" => \$gcov_tool,
+ "ignore-errors=s" => \@ignore_errors,
+ "initial|i" => \$initial,
+ "no-recursion" => \$no_recursion,
+ "no-markers" => \$no_markers,
+ "derive-func-data" => \$opt_derive_func_data,
+ "debug" => \$debug,
))
{
- print_usage(*STDERR);
+ print(STDERR "Use $tool_name --help to get usage information\n");
exit(1);
}
+else
+{
+ # Merge options
+ if (defined($no_checksum))
+ {
+ $checksum = ($no_checksum ? 0 : 1);
+ $no_checksum = undef;
+ }
+
+ if (defined($no_compat_libtool))
+ {
+ $compat_libtool = ($no_compat_libtool ? 0 : 1);
+ $no_compat_libtool = undef;
+ }
+}
@data_directory = @ARGV;
@@ -166,17 +274,29 @@
# Check for version option
if ($version)
{
- print($lcov_version."\n");
+ print("$tool_name: $lcov_version\n");
exit(0);
}
-# Adjust test name if necessary (standard for s390 architecture)
+# Make sure test names only contain valid characters
+if ($test_name =~ s/\W/_/g)
+{
+ warn("WARNING: invalid characters removed from testname!\n");
+}
+
+# Adjust test name to include uname output if requested
if ($adjust_testname)
{
$test_name .= "__".`uname -a`;
$test_name =~ s/\W/_/g;
}
+# Make sure base_directory contains an absolute path specification
+if ($base_directory)
+{
+ $base_directory = solve_relative_path($cwd, $base_directory);
+}
+
# Check for follow option
if ($follow)
{
@@ -187,12 +307,44 @@
$follow = "";
}
+# Determine checksum mode
+if (defined($checksum))
+{
+ # Normalize to boolean
+ $checksum = ($checksum ? 1 : 0);
+}
+else
+{
+ # Default is off
+ $checksum = 0;
+}
+
+# Determine libtool compatibility mode
+if (defined($compat_libtool))
+{
+ $compat_libtool = ($compat_libtool? 1 : 0);
+}
+else
+{
+ # Default is on
+ $compat_libtool = 1;
+}
+
+# Determine max depth for recursion
+if ($no_recursion)
+{
+ $maxdepth = "-maxdepth 1";
+}
+else
+{
+ $maxdepth = "";
+}
+
# Check for directory name
if (!@data_directory)
{
- print(STDERR "No directory specified\n");
- print_usage(*STDERR);
- exit(1);
+ die("No directory specified\n".
+ "Use $tool_name --help to get usage information\n");
}
else
{
@@ -206,6 +358,32 @@
}
}
+if (@ignore_errors)
+{
+ my @expanded;
+ my $error;
+
+ # Expand comma-separated entries
+ foreach (@ignore_errors) {
+ if (/,/)
+ {
+ push(@expanded, split(",", $_));
+ }
+ else
+ {
+ push(@expanded, $_);
+ }
+ }
+
+ foreach (@expanded)
+ {
+ /^gcov$/ && do { $ignore[$ERROR_GCOV] = 1; next; } ;
+ /^source$/ && do { $ignore[$ERROR_SOURCE] = 1; next; };
+ /^graph$/ && do { $ignore[$ERROR_GRAPH] = 1; next; };
+ die("ERROR: unknown argument for --ignore-errors: $_\n");
+ }
+}
+
if (system_no_output(3, $gcov_tool, "--help") == -1)
{
die("ERROR: need tool $gcov_tool!\n");
@@ -215,7 +393,7 @@
if ($gcov_version < $GCOV_VERSION_3_4_0)
{
- if (defined($compatibility) && $compatibility eq $COMPAT_SLES9)
+ if (defined($compatibility) && $compatibility eq $COMPAT_HAMMER)
{
$data_file_extension = ".da";
$graph_file_extension = ".bbg";
@@ -232,11 +410,16 @@
$graph_file_extension = ".gcno";
}
-# Check for availability of --preserve-paths option of gcov
-if (`$gcov_tool --help` =~ /--preserve-paths/)
-{
- $preserve_paths = "--preserve-paths";
-}
+# Determine gcov options
+$gcov_caps = get_gcov_capabilities();
+push(@gcov_options, "-b") if ($gcov_caps->{'branch-probabilities'});
+push(@gcov_options, "-c") if ($gcov_caps->{'branch-counts'});
+# Below branch option is disabled due to a reported compiler bug
+# present in gcc-4.5 version and earlier. If enabled, gcov will hang on
+# such compilers. This workaround just means that lcov won't be able
+# to separate multiple branch blocks in a line.
+# push(@gcov_options, "-a") if ($gcov_caps->{'all-blocks'});
+push(@gcov_options, "-p") if ($gcov_caps->{'preserve-paths'});
# Check output filename
if (defined($output_filename) && ($output_filename ne "-"))
@@ -257,9 +440,13 @@
}
# Do something
-foreach (@data_directory)
-{
- gen_info($_);
+foreach my $entry (@data_directory) {
+ gen_info($entry);
+}
+
+if ($initial) {
+ warn("Note: --initial does not generate branch coverage ".
+ "data\n");
}
info("Finished .info-file creation\n");
@@ -276,28 +463,70 @@
sub print_usage(*)
{
local *HANDLE = $_[0];
- my $tool_name = basename($0);
print(HANDLE <<END_OF_USAGE);
Usage: $tool_name [OPTIONS] DIRECTORY
-Traverse DIRECTORY and create a .info file for each .da/.gcda file found. Note
+Traverse DIRECTORY and create a .info file for each data file found. Note
that you may specify more than one directory, all of which are then processed
sequentially.
-h, --help Print this help, then exit
-v, --version Print version number, then exit
-q, --quiet Do not print progress messages
+ -i, --initial Capture initial zero coverage data
-t, --test-name NAME Use test case name NAME for resulting data
-o, --output-filename OUTFILE Write data only to OUTFILE
-f, --follow Follow links when searching .da/.gcda files
- -n, --no-checksum Do not calculate checksum for each line
-
-See $lcov_url for more information about this tool.
+ -b, --base-directory DIR Use DIR as base directory for relative paths
+ --(no-)checksum Enable (disable) line checksumming
+ --(no-)compat-libtool Enable (disable) libtool compatibility mode
+ --gcov-tool TOOL Specify gcov tool location
+ --ignore-errors ERROR Continue after ERROR (gcov, source, graph)
+ --no-recursion Exclude subdirectories from processing
+ --function-coverage Capture function call counts
+ --no-markers Ignore exclusion markers in source code
+ --derive-func-data Generate function data from line data
+
+For more information see: $lcov_url
END_OF_USAGE
;
}
+#
+# get_common_prefix(min_dir, filenames)
+#
+# Return the longest path prefix shared by all filenames. MIN_DIR specifies
+# the minimum number of directories that a filename may have after removing
+# the prefix.
+#
+
+sub get_common_prefix($@)
+{
+ my ($min_dir, @files) = @_;
+ my $file;
+ my @prefix;
+ my $i;
+
+ foreach $file (@files) {
+ my ($v, $d, $f) = splitpath($file);
+ my @comp = splitdir($d);
+
+ if (!@prefix) {
+ @prefix = @comp;
+ next;
+ }
+ for ($i = 0; $i < scalar(@comp) && $i < scalar(@prefix); $i++) {
+ if ($comp[$i] ne $prefix[$i] ||
+ ((scalar(@comp) - ($i + 1)) <= $min_dir)) {
+ delete(@prefix[$i..scalar(@prefix)]);
+ last;
+ }
+ }
+ }
+
+ return catdir(@prefix);
+}
#
# gen_info(directory)
@@ -336,76 +565,199 @@
{
my $directory = $_[0];
my @file_list;
+ my $file;
+ my $prefix;
+ my $type;
+ my $ext;
+
+ if ($initial) {
+ $type = "graph";
+ $ext = $graph_file_extension;
+ } else {
+ $type = "data";
+ $ext = $data_file_extension;
+ }
if (-d $directory)
{
- info("Scanning $directory for $data_file_extension ".
- "files ...\n");
-
- @file_list = `find $directory $follow -name \\*$data_file_extension -type f 2>/dev/null`;
+ info("Scanning $directory for $ext files ...\n");
+
+ @file_list = `find "$directory" $maxdepth $follow -name \\*$ext -type f 2>/dev/null`;
chomp(@file_list);
- @file_list or die("ERROR: no $data_file_extension files found ".
- "in $directory!\n");
- info("Found %d data files in %s\n", $#file_list+1, $directory);
+ @file_list or
+ die("ERROR: no $ext files found in $directory!\n");
+ $prefix = get_common_prefix(1, @file_list);
+ info("Found %d %s files in %s\n", $#file_list+1, $type,
+ $directory);
}
else
{
@file_list = ($directory);
+ $prefix = "";
}
# Process all files in list
- foreach (@file_list) { process_dafile($_); }
+ foreach $file (@file_list) {
+ # Process file
+ if ($initial) {
+ process_graphfile($file, $prefix);
+ } else {
+ process_dafile($file, $prefix);
+ }
+ }
}
+sub derive_data($$$)
+{
+ my ($contentdata, $funcdata, $bbdata) = @_;
+ my @gcov_content = @{$contentdata};
+ my @gcov_functions = @{$funcdata};
+ my %fn_count;
+ my %ln_fn;
+ my $line;
+ my $maxline;
+ my %fn_name;
+ my $fn;
+ my $count;
+
+ if (!defined($bbdata)) {
+ return @gcov_functions;
+ }
+
+ # First add existing function data
+ while (@gcov_functions) {
+ $count = shift(@gcov_functions);
+ $fn = shift(@gcov_functions);
+
+ $fn_count{$fn} = $count;
+ }
+
+ # Convert line coverage data to function data
+ foreach $fn (keys(%{$bbdata})) {
+ my $line_data = $bbdata->{$fn};
+ my $line;
+
+ if ($fn eq "") {
+ next;
+ }
+ # Find the lowest line count for this function
+ $count = 0;
+ foreach $line (@$line_data) {
+ my $lcount = $gcov_content[ ( $line - 1 ) * 3 + 1 ];
+
+ if (($lcount > 0) &&
+ (($count == 0) || ($lcount < $count))) {
+ $count = $lcount;
+ }
+ }
+ $fn_count{$fn} = $count;
+ }
+
+
+ # Check if we got data for all functions
+ foreach $fn (keys(%fn_name)) {
+ if ($fn eq "") {
+ next;
+ }
+ if (defined($fn_count{$fn})) {
+ next;
+ }
+ warn("WARNING: no derived data found for function $fn\n");
+ }
+
+ # Convert hash to list in @gcov_functions format
+ foreach $fn (sort(keys(%fn_count))) {
+ push(@gcov_functions, $fn_count{$fn}, $fn);
+ }
+
+ return @gcov_functions;
+}
+
#
-# process_dafile(da_filename)
+# get_filenames(directory, pattern)
+#
+# Return a list of filenames found in directory which match the specified
+# pattern.
+#
+# Die on error.
+#
+
+sub get_filenames($$)
+{
+ my ($dirname, $pattern) = @_;
+ my @result;
+ my $directory;
+ local *DIR;
+
+ opendir(DIR, $dirname) or
+ die("ERROR: cannot read directory $dirname\n");
+ while ($directory = readdir(DIR)) {
+ push(@result, $directory) if ($directory =~ /$pattern/);
+ }
+ closedir(DIR);
+
+ return @result;
+}
+
+#
+# process_dafile(da_filename, dir)
#
# Create a .info file for a single data file.
#
# Die on error.
#
-sub process_dafile($)
+sub process_dafile($$)
{
- info("Processing %s\n", $_[0]);
-
+ my ($file, $dir) = @_;
my $da_filename; # Name of data file to process
my $da_dir; # Directory of data file
+ my $source_dir; # Directory of source file
my $da_basename; # data filename without ".da/.gcda" extension
my $bb_filename; # Name of respective graph file
- my %bb_content; # Contents of graph file
+ my $bb_basename; # Basename of the original graph file
+ my $graph; # Contents of graph file
+ my $instr; # Contents of graph file part 2
my $gcov_error; # Error code of gcov tool
my $object_dir; # Directory containing all object files
my $source_filename; # Name of a source code file
my $gcov_file; # Name of a .gcov file
my @gcov_content; # Content of a .gcov file
- my @gcov_branches; # Branch content of a .gcov file
+ my $gcov_branches; # Branch content of a .gcov file
+ my @gcov_functions; # Function calls of a .gcov file
my @gcov_list; # List of generated .gcov files
my $line_number; # Line number count
my $lines_hit; # Number of instrumented lines hit
my $lines_found; # Number of instrumented lines found
+ my $funcs_hit; # Number of instrumented functions hit
+ my $funcs_found; # Number of instrumented functions found
+ my $br_hit;
+ my $br_found;
my $source; # gcov source header information
my $object; # gcov object header information
my @matches; # List of absolute paths matching filename
my @unprocessed; # List of unprocessed source code files
+ my $base_dir; # Base directory for current file
+ my @tmp_links; # Temporary links to be cleaned up
my @result;
my $index;
my $da_renamed; # If data file is to be renamed
local *INFO_HANDLE;
+ info("Processing %s\n", abs2rel($file, $dir));
# Get path to data file in absolute and normalized form (begins with /,
# contains no more ../ or ./)
- $da_filename = solve_relative_path($cwd, $_[0]);
+ $da_filename = solve_relative_path($cwd, $file);
# Get directory and basename of data file
($da_dir, $da_basename) = split_filename($da_filename);
- # Check for writable $da_dir (gcov will try to write files there)
- stat($da_dir);
- if (!-w _)
- {
- die("ERROR: cannot write to directory $da_dir!\n");
+ # avoid files from .libs dirs
+ if ($compat_libtool && $da_dir =~ m/(.*)\/\.libs$/) {
+ $source_dir = $1;
+ } else {
+ $source_dir = $da_dir;
}
if (-z $da_filename)
@@ -417,15 +769,35 @@
$da_renamed = 0;
}
+ # Construct base_dir for current file
+ if ($base_directory)
+ {
+ $base_dir = $base_directory;
+ }
+ else
+ {
+ $base_dir = $source_dir;
+ }
+
+ # Check for writable $base_dir (gcov will try to write files there)
+ stat($base_dir);
+ if (!-w _)
+ {
+ die("ERROR: cannot write to directory $base_dir!\n");
+ }
+
# Construct name of graph file
- $bb_filename = $da_dir."/".$da_basename.$graph_file_extension;
-
+ $bb_basename = $da_basename.$graph_file_extension;
+ $bb_filename = "$da_dir/$bb_basename";
# Find out the real location of graph file in case we're just looking at
# a link
while (readlink($bb_filename))
{
+ my $last_dir = dirname($bb_filename);
+
$bb_filename = readlink($bb_filename);
+ $bb_filename = solve_relative_path($last_dir, $bb_filename);
}
# Ignore empty graph file (e.g. source file with no statement)
@@ -440,27 +812,27 @@
# information about functions and their source code positions.
if ($gcov_version < $GCOV_VERSION_3_4_0)
{
- if (defined($compatibility) && $compatibility eq $COMPAT_SLES9)
+ if (defined($compatibility) && $compatibility eq $COMPAT_HAMMER)
{
- %bb_content = read_sles9_bbg_file($bb_filename);
+ ($instr, $graph) = read_bbg($bb_filename, $base_dir);
}
else
{
- %bb_content = read_bb_file($bb_filename);
+ ($instr, $graph) = read_bb($bb_filename, $base_dir);
}
}
else
{
- %bb_content = read_gcno_file($bb_filename);
+ ($instr, $graph) = read_gcno($bb_filename, $base_dir);
}
# Set $object_dir to real location of object files. This may differ
# from $da_dir if the graph file is just a link to the "real" object
- # file location. We need to apply GCOV with using that directory to
- # ensure that all relative #include-files are found as well.
- ($object_dir) = split_filename($bb_filename);
-
- # Is the data file in the same directory with all the other files?
+ # file location.
+ $object_dir = dirname($bb_filename);
+
+ # Is the data file in a different directory? (this happens e.g. with
+ # the gcov-kernel patch)
if ($object_dir ne $da_dir)
{
# Need to create link to data file in $object_dir
@@ -468,10 +840,21 @@
"$object_dir/$da_basename$data_file_extension")
and die ("ERROR: cannot create link $object_dir/".
"$da_basename$data_file_extension!\n");
+ push(@tmp_links,
+ "$object_dir/$da_basename$data_file_extension");
+ # Need to create link to graph file if basename of link
+ # and file are different (CONFIG_MODVERSION compat)
+ if ((basename($bb_filename) ne $bb_basename) &&
+ (! -e "$object_dir/$bb_basename")) {
+ symlink($bb_filename, "$object_dir/$bb_basename") or
+ warn("WARNING: cannot create link ".
+ "$object_dir/$bb_basename\n");
+ push(@tmp_links, "$object_dir/$bb_basename");
+ }
}
# Change to directory containing data files and apply GCOV
- #chdir($object_dir);
+ chdir($base_dir);
if ($da_renamed)
{
@@ -482,19 +865,8 @@
}
# Execute gcov command and suppress standard output
- if ($preserve_paths)
- {
- $gcov_error = system_no_output(1, $gcov_tool, $da_basename.".c",
- "-o", $object_dir,
- "--preserve-paths",
- "-b");
- }
- else
- {
- $gcov_error = system_no_output(1, $gcov_tool, $da_basename.".c",
- "-o", $object_dir,
- "-b");
- }
+ $gcov_error = system_no_output(1, $gcov_tool, $da_filename,
+ "-o", $object_dir, @gcov_options);
if ($da_renamed)
{
@@ -502,16 +874,23 @@
and die ("ERROR: cannot rename $da_filename.ori");
}
- # Clean up link
- if ($object_dir ne $da_dir)
+ # Clean up temporary links
+ foreach (@tmp_links) {
+ unlink($_);
+ }
+
+ if ($gcov_error)
{
- unlink($object_dir."/".$da_basename.$data_file_extension);
+ if ($ignore[$ERROR_GCOV])
+ {
+ warn("WARNING: GCOV failed for $da_filename!\n");
+ return;
+ }
+ die("ERROR: GCOV failed for $da_filename!\n");
}
- $gcov_error and die("ERROR: GCOV failed for $da_filename!\n");
-
# Collect data from resulting .gcov files and create .info file
- @gcov_list = glob("*.gcov");
+ @gcov_list = get_filenames('.', '\.gcov$');
# Check for files
if (!@gcov_list)
@@ -547,26 +926,35 @@
# Traverse the list of generated .gcov files and combine them into a
# single .info file
- @unprocessed = keys(%bb_content);
- foreach $gcov_file (@gcov_list)
+ @unprocessed = keys(%{$instr});
+ foreach $gcov_file (sort(@gcov_list))
{
+ my $i;
+ my $num;
+
($source, $object) = read_gcov_header($gcov_file);
- if ($source)
+ if (defined($source))
{
- $source = solve_relative_path($object_dir, $source);
+ $source = solve_relative_path($base_dir, $source);
}
# gcov will happily create output even if there's no source code
- # available - this interfers with checksum creation so we need
+ # available - this interferes with checksum creation so we need
# to pull the emergency brake here.
- if (defined($source) && ! -r $source && ! $nochecksum)
+ if (defined($source) && ! -r $source && $checksum)
{
+ if ($ignore[$ERROR_SOURCE])
+ {
+ warn("WARNING: could not read source file ".
+ "$source\n");
+ next;
+ }
die("ERROR: could not read source file $source\n");
}
@matches = match_filename(defined($source) ? $source :
- $gcov_file, keys(%bb_content));
+ $gcov_file, keys(%{$instr}));
# Skip files that are not mentioned in the graph file
if (!@matches)
@@ -580,8 +968,15 @@
# Read in contents of gcov file
@result = read_gcov_file($gcov_file);
+ if (!defined($result[0])) {
+ warn("WARNING: skipping unreadable file ".
+ $gcov_file."\n");
+ unlink($gcov_file);
+ next;
+ }
@gcov_content = @{$result[0]};
- @gcov_branches = @{$result[1]};
+ $gcov_branches = $result[1];
+ @gcov_functions = @{$result[2]};
# Skip empty files
if (!@gcov_content)
@@ -616,15 +1011,96 @@
# Write absolute path of source file
printf(INFO_HANDLE "SF:%s\n", $source_filename);
+ # If requested, derive function coverage data from
+ # line coverage data of the first line of a function
+ if ($opt_derive_func_data) {
+ @gcov_functions =
+ derive_data(\@gcov_content, \@gcov_functions,
+ $graph->{$source_filename});
+ }
+
# Write function-related information
- foreach (split(",",$bb_content{$source_filename}))
+ if (defined($graph->{$source_filename}))
{
- # Write "line_number,function_name" for each function.
- # Note that $_ contains this information in the form
- # "function_name=line_number" so that the order of
- # elements has to be reversed.
- printf(INFO_HANDLE "FN:%s\n",
- join(",", (split("=", $_))[1,0]));
+ my $fn_data = $graph->{$source_filename};
+ my $fn;
+
+ foreach $fn (sort
+ {$fn_data->{$a}->[0] <=> $fn_data->{$b}->[0]}
+ keys(%{$fn_data})) {
+ my $ln_data = $fn_data->{$fn};
+ my $line = $ln_data->[0];
+
+ # Skip empty function
+ if ($fn eq "") {
+ next;
+ }
+ # Remove excluded functions
+ if (!$no_markers) {
+ my $gfn;
+ my $found = 0;
+
+ foreach $gfn (@gcov_functions) {
+ if ($gfn eq $fn) {
+ $found = 1;
+ last;
+ }
+ }
+ if (!$found) {
+ next;
+ }
+ }
+
+ # Normalize function name
+ $fn = filter_fn_name($fn);
+
+ print(INFO_HANDLE "FN:$line,$fn\n");
+ }
+ }
+
+ #--
+ #-- FNDA: <call-count>, <function-name>
+ #-- FNF: overall count of functions
+ #-- FNH: overall count of functions with non-zero call count
+ #--
+ $funcs_found = 0;
+ $funcs_hit = 0;
+ while (@gcov_functions)
+ {
+ my $count = shift(@gcov_functions);
+ my $fn = shift(@gcov_functions);
+
+ $fn = filter_fn_name($fn);
+ printf(INFO_HANDLE "FNDA:$count,$fn\n");
+ $funcs_found++;
+ $funcs_hit++ if ($count > 0);
+ }
+ if ($funcs_found > 0) {
+ printf(INFO_HANDLE "FNF:%s\n", $funcs_found);
+ printf(INFO_HANDLE "FNH:%s\n", $funcs_hit);
+ }
+
+ # Write coverage information for each instrumented branch:
+ #
+ # BRDA:<line number>,<block number>,<branch number>,<taken>
+ #
+ # where 'taken' is the number of times the branch was taken
+ # or '-' if the block to which the branch belongs was never
+ # executed
+ $br_found = 0;
+ $br_hit = 0;
+ $num = br_gvec_len($gcov_branches);
+ for ($i = 0; $i < $num; $i++) {
+ my ($line, $block, $branch, $taken) =
+ br_gvec_get($gcov_branches, $i);
+
+ print(INFO_HANDLE "BRDA:$line,$block,$branch,$taken\n");
+ $br_found++;
+ $br_hit++ if ($taken ne '-' && $taken > 0);
+ }
+ if ($br_found > 0) {
+ printf(INFO_HANDLE "BRF:%s\n", $br_found);
+ printf(INFO_HANDLE "BRH:%s\n", $br_hit);
}
# Reset line counters
@@ -644,8 +1120,8 @@
{
$lines_found++;
printf(INFO_HANDLE "DA:".$line_number.",".
- $gcov_content[1].($nochecksum ? "" :
- ",". md5_base64($gcov_content[2])).
+ $gcov_content[1].($checksum ?
+ ",". md5_base64($gcov_content[2]) : "").
"\n");
# Increase $lines_hit in case of an execution
@@ -657,27 +1133,6 @@
splice(@gcov_content,0,3);
}
- #--
- #-- BA: <code-line>, <branch-coverage>
- #--
- #-- print one BA line for every branch of a
- #-- conditional. <branch-coverage> values
- #-- are:
- #-- 0 - not executed
- #-- 1 - executed but not taken
- #-- 2 - executed and taken
- #--
- while (@gcov_branches)
- {
- if ($gcov_branches[0])
- {
- printf(INFO_HANDLE "BA:%s,%s\n",
- $gcov_branches[0],
- $gcov_branches[1]);
- }
- splice(@gcov_branches,0,2);
- }
-
# Write line statistics and section separator
printf(INFO_HANDLE "LF:%s\n", $lines_found);
printf(INFO_HANDLE "LH:%s\n", $lines_hit);
@@ -707,28 +1162,6 @@
}
-# cleanup_path (path)
-sub cleanup_path($@)
-{
- my $result = shift @_;
-
- # Remove //
- $result =~ s/\/\//\//g;
-
- # Remove .
- $result =~ s/\/\.\//\//g;
-
- # Solve ..
- while ($result =~ s/\/[^\/]+\/\.\.\//\//)
- {
- }
-
- # Remove preceding ..
- $result =~ s/^\/\.\.\//\//g;
-
- return $result;
-}
-
#
# solve_relative_path(path, dir)
#
@@ -748,17 +1181,19 @@
$result = "$path/$result";
}
- $result = cleanup_path ($result);
-
- if (-f $result) {
- return $result;
+ # Remove //
+ $result =~ s/\/\//\//g;
+
+ # Remove .
+ $result =~ s/\/\.\//\//g;
+
+ # Solve ..
+ while ($result =~ s/\/[^\/]+\/\.\.\//\//)
+ {
}
- for my $prefix (split (':', $source_dirs)) {
- $result = cleanup_path ("$prefix/$dir");
- if (-f $result) {
- return $result;
- }
- }
+
+ # Remove preceding ..
+ $result =~ s/^\/\.\.\//\//g;
return $result;
}
@@ -773,28 +1208,42 @@
sub match_filename($@)
{
- my $filename = shift;
- my @list = @_;
+ my ($filename, @list) = @_;
+ my ($vol, $dir, $file) = splitpath($filename);
+ my @comp = splitdir($dir);
+ my $comps = scalar(@comp);
+ my $entry;
my @result;
- $filename =~ s/^(.*).gcov$/$1/;
-
- if ($filename =~ /^\/(.*)$/)
- {
- $filename = "$1";
+entry:
+ foreach $entry (@list) {
+ my ($evol, $edir, $efile) = splitpath($entry);
+ my @ecomp;
+ my $ecomps;
+ my $i;
+
+ # Filename component must match
+ if ($efile ne $file) {
+ next;
+ }
+ # Check directory components last to first for match
+ @ecomp = splitdir($edir);
+ $ecomps = scalar(@ecomp);
+ if ($ecomps < $comps) {
+ next;
+ }
+ for ($i = 0; $i < $comps; $i++) {
+ if ($comp[$comps - $i - 1] ne
+ $ecomp[$ecomps - $i - 1]) {
+ next entry;
+ }
+ }
+ push(@result, $entry),
}
- foreach (@list)
- {
- if (/\/\Q$filename\E(.*)$/ && $1 eq "")
- {
- @result = (@result, $_);
- }
- }
return @result;
}
-
#
# solve_ambiguous_match(rel_filename, matches_ref, gcov_content_ref)
#
@@ -829,6 +1278,9 @@
{
chomp;
+ # Also remove CR from line-end
+ s/\015$//;
+
if ($_ ne @$content[$index])
{
$no_match = 1;
@@ -867,21 +1319,6 @@
#
-# get_dir(filename);
-#
-# Return the directory component of a given FILENAME.
-#
-
-sub get_dir($)
-{
- my @components = split("/", $_[0]);
- pop(@components);
-
- return join("/", @components);
-}
-
-
-#
# read_gcov_header(gcov_filename)
#
# Parse file GCOV_FILENAME and return a list containing the following
@@ -903,13 +1340,23 @@
my $object;
local *INPUT;
- open(INPUT, $_[0])
- or die("ERROR: cannot read $_[0]!\n");
+ if (!open(INPUT, $_[0]))
+ {
+ if ($ignore_errors[$ERROR_GCOV])
+ {
+ warn("WARNING: cannot read $_[0]!\n");
+ return (undef,undef);
+ }
+ die("ERROR: cannot read $_[0]!\n");
+ }
while (<INPUT>)
{
chomp($_);
+ # Also remove CR from line-end
+ s/\015$//;
+
if (/^\s+-:\s+0:Source:(.*)$/)
{
# Source: header entry
@@ -933,10 +1380,88 @@
#
+# br_gvec_len(vector)
+#
+# Return the number of entries in the branch coverage vector.
+#
+
+sub br_gvec_len($)
+{
+ my ($vec) = @_;
+
+ return 0 if (!defined($vec));
+ return (length($vec) * 8 / $BR_VEC_WIDTH) / $BR_VEC_ENTRIES;
+}
+
+
+#
+# br_gvec_get(vector, number)
+#
+# Return an entry from the branch coverage vector.
+#
+
+sub br_gvec_get($$)
+{
+ my ($vec, $num) = @_;
+ my $line;
+ my $block;
+ my $branch;
+ my $taken;
+ my $offset = $num * $BR_VEC_ENTRIES;
+
+ # Retrieve data from vector
+ $line = vec($vec, $offset + $BR_LINE, $BR_VEC_WIDTH);
+ $block = vec($vec, $offset + $BR_BLOCK, $BR_VEC_WIDTH);
+ $branch = vec($vec, $offset + $BR_BRANCH, $BR_VEC_WIDTH);
+ $taken = vec($vec, $offset + $BR_TAKEN, $BR_VEC_WIDTH);
+
+ # Decode taken value from an integer
+ if ($taken == 0) {
+ $taken = "-";
+ } else {
+ $taken--;
+ }
+
+ return ($line, $block, $branch, $taken);
+}
+
+
+#
+# br_gvec_push(vector, line, block, branch, taken)
+#
+# Add an entry to the branch coverage vector.
+#
+
+sub br_gvec_push($$$$$)
+{
+ my ($vec, $line, $block, $branch, $taken) = @_;
+ my $offset;
+
+ $vec = "" if (!defined($vec));
+ $offset = br_gvec_len($vec) * $BR_VEC_ENTRIES;
+
+ # Encode taken value into an integer
+ if ($taken eq "-") {
+ $taken = 0;
+ } else {
+ $taken++;
+ }
+
+ # Add to vector
+ vec($vec, $offset + $BR_LINE, $BR_VEC_WIDTH) = $line;
+ vec($vec, $offset + $BR_BLOCK, $BR_VEC_WIDTH) = $block;
+ vec($vec, $offset + $BR_BRANCH, $BR_VEC_WIDTH) = $branch;
+ vec($vec, $offset + $BR_TAKEN, $BR_VEC_WIDTH) = $taken;
+
+ return $vec;
+}
+
+
+#
# read_gcov_file(gcov_filename)
#
# Parse file GCOV_FILENAME (.gcov file format) and return the list:
-# (reference to gcov_content, reference to gcov_branch)
+# (reference to gcov_content, reference to gcov_branch, reference to gcov_func)
#
# gcov_content is a list of 3 elements
# (flag, count, source) for each source code line:
@@ -945,8 +1470,11 @@
# $result[($line_number-1)*3+1] = execution count for line $line_number
# $result[($line_number-1)*3+2] = source code text for line $line_number
#
-# gcov_branch is a list of 2 elements
-# (linenumber, branch result) for each branch
+# gcov_branch is a vector of 4 4-byte long elements for each branch:
+# line number, block number, branch number, count + 1 or 0
+#
+# gcov_func is a list of 2 elements
+# (number of calls, function name) for each function
#
# Die on error.
#
@@ -955,12 +1483,23 @@
{
my $filename = $_[0];
my @result = ();
- my @branches = ();
+ my $branches = "";
+ my @functions = ();
my $number;
+ my $exclude_flag = 0;
+ my $exclude_line = 0;
+ my $last_block = $UNNAMED_BLOCK;
+ my $last_line = 0;
local *INPUT;
- open(INPUT, $filename)
- or die("ERROR: cannot read $filename!\n");
+ if (!open(INPUT, $filename)) {
+ if ($ignore_errors[$ERROR_GCOV])
+ {
+ warn("WARNING: cannot read $filename!\n");
+ return (undef, undef, undef);
+ }
+ die("ERROR: cannot read $filename!\n");
+ }
if ($gcov_version < $GCOV_VERSION_3_3_0)
{
@@ -969,45 +1508,61 @@
{
chomp($_);
- if (/^\t\t(.*)$/)
- {
- # Uninstrumented line
- push(@result, 0);
- push(@result, 0);
- push(@result, $1);
+ # Also remove CR from line-end
+ s/\015$//;
+
+ if (/^branch\s+(\d+)\s+taken\s+=\s+(\d+)/) {
+ next if ($exclude_line);
+ $branches = br_gvec_push($branches, $last_line,
+ $last_block, $1, $2);
+ } elsif (/^branch\s+(\d+)\s+never\s+executed/) {
+ next if ($exclude_line);
+ $branches = br_gvec_push($branches, $last_line,
+ $last_block, $1, '-');
}
- elsif (/^branch/)
- {
- # Branch execution data
- push(@branches, scalar(@result) / 3);
- if (/^branch \d+ never executed$/)
- {
- push(@branches, 0);
- }
- elsif (/^branch \d+ taken = 0%/)
- {
- push(@branches, 1);
- }
- else
- {
- push(@branches, 2);
- }
- }
- elsif (/^call/)
+ elsif (/^call/ || /^function/)
{
# Function call return data
}
else
{
+ $last_line++;
+ # Check for exclusion markers
+ if (!$no_markers) {
+ if (/$EXCL_STOP/) {
+ $exclude_flag = 0;
+ } elsif (/$EXCL_START/) {
+ $exclude_flag = 1;
+ }
+ if (/$EXCL_LINE/ || $exclude_flag) {
+ $exclude_line = 1;
+ } else {
+ $exclude_line = 0;
+ }
+ }
# Source code execution data
+ if (/^\t\t(.*)$/)
+ {
+ # Uninstrumented line
+ push(@result, 0);
+ push(@result, 0);
+ push(@result, $1);
+ next;
+ }
$number = (split(" ",substr($_, 0, 16)))[0];
# Check for zero count which is indicated
# by ######
if ($number eq "######") { $number = 0; }
- push(@result, 1);
- push(@result, $number);
+ if ($exclude_line) {
+ # Register uninstrumented line instead
+ push(@result, 0);
+ push(@result, 0);
+ } else {
+ push(@result, 1);
+ push(@result, $number);
+ }
push(@result, substr($_, 16));
}
}
@@ -1019,22 +1574,29 @@
{
chomp($_);
- if (/^branch\s+\d+\s+(\S+)\s+(\S+)/)
+ # Also remove CR from line-end
+ s/\015$//;
+
+ if (/^\s*(\d+|\$+):\s*(\d+)-block\s+(\d+)\s*$/) {
+ # Block information - used to group related
+ # branches
+ $last_line = $2;
+ $last_block = $3;
+ } elsif (/^branch\s+(\d+)\s+taken\s+(\d+)/) {
+ next if ($exclude_line);
+ $branches = br_gvec_push($branches, $last_line,
+ $last_block, $1, $2);
+ } elsif (/^branch\s+(\d+)\s+never\s+executed/) {
+ next if ($exclude_line);
+ $branches = br_gvec_push($branches, $last_line,
+ $last_block, $1, '-');
+ }
+ elsif (/^function\s+(\S+)\s+called\s+(\d+)/)
{
- # Branch execution data
- push(@branches, scalar(@result) / 3);
- if ($1 eq "never")
- {
- push(@branches, 0);
+ if ($exclude_line) {
+ next;
}
- elsif ($2 eq "0%")
- {
- push(@branches, 1);
- }
- else
- {
- push(@branches, 2);
- }
+ push(@functions, $2, $1);
}
elsif (/^call/)
{
@@ -1042,515 +1604,59 @@
}
elsif (/^\s*([^:]+):\s*([^:]+):(.*)$/)
{
+ my ($count, $line, $code) = ($1, $2, $3);
+
+ $last_line = $line;
+ $last_block = $UNNAMED_BLOCK;
+ # Check for exclusion markers
+ if (!$no_markers) {
+ if (/$EXCL_STOP/) {
+ $exclude_flag = 0;
+ } elsif (/$EXCL_START/) {
+ $exclude_flag = 1;
+ }
+ if (/$EXCL_LINE/ || $exclude_flag) {
+ $exclude_line = 1;
+ } else {
+ $exclude_line = 0;
+ }
+ }
# <exec count>:<line number>:<source code>
- if ($2 eq "0")
+ if ($line eq "0")
{
# Extra data
}
- elsif ($1 eq "-")
+ elsif ($count eq "-")
{
# Uninstrumented line
push(@result, 0);
push(@result, 0);
- push(@result, $3);
+ push(@result, $code);
}
else
{
- # Source code execution data
- $number = $1;
-
- # Check for zero count
- if ($number eq "#####") { $number = 0; }
-
- push(@result, 1);
- push(@result, $number);
- push(@result, $3);
+ if ($exclude_line) {
+ push(@result, 0);
+ push(@result, 0);
+ } else {
+ # Check for zero count
+ if ($count eq "#####") {
+ $count = 0;
+ }
+ push(@result, 1);
+ push(@result, $count);
+ }
+ push(@result, $code);
}
}
}
}
close(INPUT);
- return(\@result, \@branches);
-}
-
-
-#
-# read_bb_file(bb_filename)
-#
-# Read .bb file BB_FILENAME and return a hash containing the following
-# mapping:
-#
-# filename -> comma-separated list of pairs (function name=starting
-# line number) for each function found
-#
-# for each entry in the .bb file. Filenames are absolute, i.e. relative
-# filenames are prefixed with bb_filename's path component.
-#
-# Die on error.
-#
-
-sub read_bb_file($)
-{
- my $bb_filename = $_[0];
- my %result;
- my $filename;
- my $function_name;
- my $cwd = `pwd`;
- chomp($cwd);
- my $base_dir = get_dir(solve_relative_path(
- $cwd, $bb_filename));
- my $minus_one = sprintf("%d", 0x80000001);
- my $minus_two = sprintf("%d", 0x80000002);
- my $value;
- my $packed_word;
- local *INPUT;
-
- open(INPUT, $bb_filename)
- or die("ERROR: cannot read $bb_filename!\n");
-
- binmode(INPUT);
-
- # Read data in words of 4 bytes
- while (read(INPUT, $packed_word, 4) == 4)
- {
- # Decode integer in intel byteorder
- $value = unpack_int32($packed_word, 0);
-
- # Note: the .bb file format is documented in GCC info pages
- if ($value == $minus_one)
- {
- # Filename follows
- $filename = read_string(*INPUT, $minus_one)
- or die("ERROR: incomplete filename in ".
- "$bb_filename!\n");
-
- # Make path absolute
- $filename = solve_relative_path($base_dir, $filename);
-
- # Insert into hash if not yet present.
- # This is necessary because functions declared as
- # "inline" are not listed as actual functions in
- # .bb files
- if (!$result{$filename})
- {
- $result{$filename}="";
- }
- }
- elsif ($value == $minus_two)
- {
- # Function name follows
- $function_name = read_string(*INPUT, $minus_two)
- or die("ERROR: incomplete function ".
- "name in $bb_filename!\n");
- }
- elsif ($value > 0)
- {
- if ($function_name)
- {
- # Got a full entry filename, funcname, lineno
- # Add to resulting hash
-
- $result{$filename}.=
- ($result{$filename} ? "," : "").
- join("=",($function_name,$value));
- undef($function_name);
- }
- }
- }
- close(INPUT);
-
- if (!scalar(keys(%result)))
- {
- die("ERROR: no data found in $bb_filename!\n");
- }
- return %result;
-}
-
-
-#
-# read_string(handle, delimiter);
-#
-# Read and return a string in 4-byte chunks from HANDLE until DELIMITER
-# is found.
-#
-# Return empty string on error.
-#
-
-sub read_string(*$)
-{
- my $HANDLE = $_[0];
- my $delimiter = $_[1];
- my $string = "";
- my $packed_word;
- my $value;
-
- while (read($HANDLE,$packed_word,4) == 4)
- {
- $value = unpack_int32($packed_word, 0);
-
- if ($value == $delimiter)
- {
- # Remove trailing nil bytes
- $/="\0";
- while (chomp($string)) {};
- $/="\n";
- return($string);
- }
-
- $string = $string.$packed_word;
+ if ($exclude_flag) {
+ warn("WARNING: unterminated exclusion section in $filename\n");
}
- return("");
-}
-
-
-#
-# read_gcno_file(bb_filename)
-#
-# Read .gcno file BB_FILENAME and return a hash containing the following
-# mapping:
-#
-# filename -> comma-separated list of pairs (function name=starting
-# line number) for each function found
-#
-# for each entry in the .gcno file. Filenames are absolute, i.e. relative
-# filenames are prefixed with bb_filename's path component.
-#
-# Die on error.
-#
-
-sub read_gcno_file($)
-{
- my $gcno_filename = $_[0];
- my %result;
- my $filename;
- my $function_name;
- my $lineno;
- my $length;
- my $cwd = `pwd`;
- my $value;
- my $endianness;
- my $blocks;
- chomp($cwd);
- my $base_dir = get_dir(solve_relative_path(
- $cwd, $gcno_filename));
- my $packed_word;
- local *INPUT;
-
- open(INPUT, $gcno_filename)
- or die("ERROR: cannot read $gcno_filename!\n");
-
- binmode(INPUT);
-
- read(INPUT, $packed_word, 4) == 4
- or die("ERROR: Invalid gcno file format\n");
-
- $value = unpack_int32($packed_word, 0);
- $endianness = !($value == $GCNO_FILE_MAGIC);
-
- unpack_int32($packed_word, $endianness) == $GCNO_FILE_MAGIC
- or die("ERROR: gcno file magic does not match\n");
-
- seek(INPUT, 8, 1);
-
- # Read data in words of 4 bytes
- while (read(INPUT, $packed_word, 4) == 4)
- {
- # Decode integer in intel byteorder
- $value = unpack_int32($packed_word, $endianness);
-
- if ($value == $GCNO_FUNCTION_TAG)
- {
- # skip length, ident and checksum
- seek(INPUT, 12, 1);
- (undef, $function_name) =
- read_gcno_string(*INPUT, $endianness);
- (undef, $filename) =
- read_gcno_string(*INPUT, $endianness);
- $filename = solve_relative_path($base_dir, $filename);
-
- read(INPUT, $packed_word, 4);
- $lineno = unpack_int32($packed_word, $endianness);
-
- $result{$filename}.=
- ($result{$filename} ? "," : "").
- join("=",($function_name,$lineno));
- }
- elsif ($value == $GCNO_LINES_TAG)
- {
- # Check for names of files containing inlined code
- # included in this file
- read(INPUT, $packed_word, 4);
- $length = unpack_int32($packed_word, $endianness);
- while ($length > 0)
- {
- read(INPUT, $packed_word, 4);
- $lineno = unpack_int32($packed_word,
- $endianness);
- $length--;
- if ($lineno != 0)
- {
- next;
- }
- #added because if length is zero the following
- #reading process will die, it will read garbage
- if ($length == 0)
- {
- next;
- }
- ($blocks, $filename) =
- read_gcno_string(*INPUT, $endianness);
- if ($blocks > 1)
- {
- $filename = solve_relative_path(
- $base_dir, $filename);
- if (!defined($result{$filename}))
- {
- $result{$filename} = "";
- }
- }
- $length -= $blocks;
- }
- }
- else
- {
- read(INPUT, $packed_word, 4);
- $length = unpack_int32($packed_word, $endianness);
- seek(INPUT, 4 * $length, 1);
- }
- }
- close(INPUT);
-
- if (!scalar(keys(%result)))
- {
- die("ERROR: no data found in $gcno_filename!\n");
- }
- return %result;
-}
-
-
-#
-# read_gcno_string(handle, endianness);
-#
-# Read a string in 4-byte chunks from HANDLE.
-#
-# Return (number of 4-byte chunks read, string).
-#
-
-sub read_gcno_string(*$)
-{
- my $handle = $_[0];
- my $endianness = $_[1];
- my $number_of_blocks = 0;
- my $string = "";
- my $packed_word;
-
- read($handle, $packed_word, 4) == 4
- or die("ERROR: reading string\n");
-
- $number_of_blocks = unpack_int32($packed_word, $endianness);
-
- if ($number_of_blocks == 0)
- {
- return (1, undef);
- }
-
- read($handle, $packed_word, 4 * $number_of_blocks) ==
- 4 * $number_of_blocks or die("ERROR: reading string\n");
-
- $string = $string . $packed_word;
-
- # Remove trailing nil bytes
- $/="\0";
- while (chomp($string)) {};
- $/="\n";
-
- return(1 + $number_of_blocks, $string);
-}
-
-
-#
-# read_sles9_bbg_file(bb_filename)
-#
-# Read .bbg file BB_FILENAME and return a hash containing the following
-# mapping:
-#
-# filename -> comma-separated list of pairs (function name=starting
-# line number) for each function found
-#
-# for each entry in the .bbg file. Filenames are absolute, i.e. relative
-# filenames are prefixed with bb_filename's path component.
-#
-# Die on error.
-#
-
-sub read_sles9_bbg_file($)
-{
- my $bbg_filename = $_[0];
- my %result;
- my $filename;
- my $function_name;
- my $first_line;
- my $lineno;
- my $length;
- my $cwd = `pwd`;
- my $value;
- my $endianness;
- my $blocks;
- chomp($cwd);
- my $base_dir = get_dir(solve_relative_path($cwd, $bbg_filename));
- my $packed_word;
- local *INPUT;
-
- open(INPUT, $bbg_filename)
- or die("ERROR: cannot read $bbg_filename!\n");
-
- binmode(INPUT);
-
- read(INPUT, $packed_word, 4) == 4
- or die("ERROR: invalid bbg file format\n");
-
- $value = unpack_int32($packed_word, 0);
- $endianness = 1;
-
- unpack_int32($packed_word, $endianness) == $BBG_FILE_MAGIC
- or die("ERROR: bbg file magic does not match\n");
-
- seek(INPUT, 4, 1);
-
- # Read data in words of 4 bytes
- while (read(INPUT, $packed_word, 4) == 4)
- {
- # Decode integer in intel byteorder
- $value = unpack_int32($packed_word, $endianness);
-
- # Get record length
- read(INPUT, $packed_word, 4);
- $length = unpack_int32($packed_word, $endianness);
-
- if ($value == $GCNO_FUNCTION_TAG)
- {
- # Get function name
- ($value, $function_name) =
- read_sles9_bbg_string(*INPUT, $endianness);
-
- seek(INPUT, $length - $value * 4, 1);
- }
- elsif ($value == $GCNO_LINES_TAG)
- {
- # Get linenumber and filename
-
- # Skip block number
- seek(INPUT, 4, 1);
- $length -= 4;
-
- while ($length > 0)
- {
- read(INPUT, $packed_word, 4);
- $lineno = unpack_int32($packed_word,
- $endianness);
- $length -= 4;
- if ($lineno != 0)
- {
- if (!defined($first_line))
- {
- $first_line = $lineno;
- }
- next;
- }
- ($blocks, $value) =
- read_sles9_bbg_string(
- *INPUT, $endianness);
- if (!defined($filename))
- {
- $filename = $value;
- }
- $length -= $blocks * 4;
- }
- # Got a complete data set?
- if (defined($filename) && defined($function_name) &&
- defined($first_line))
- {
- $filename = solve_relative_path(
- $base_dir, $filename);
- # Add it to our result hash
- if (defined($result{$filename}))
- {
- $result{$filename} .=
- ",$function_name=$first_line";
- }
- else
- {
- $result{$filename} =
- "$function_name=$first_line";
- }
- $filename = undef;
- $function_name = undef;
- $first_line = undef;
- }
- }
- else
- {
- # Skip other records
- seek(INPUT, $length, 1);
- }
- }
- close(INPUT);
-
- if (!scalar(keys(%result)))
- {
- die("ERROR: no data found in $bbg_filename!\n");
- }
- return %result;
-}
-
-
-#
-# read_sles9_bbg_string(handle, endianness);
-#
-# Read a string in 4-byte chunks from HANDLE.
-#
-# Return (number of 4-byte chunks read, string).
-#
-
-sub read_sles9_bbg_string(*$)
-{
- my $handle = $_[0];
- my $endianness = $_[1];
- my $length = 0;
- my $string = "";
- my $packed_word;
- my $pad;
-
- read($handle, $packed_word, 4) == 4
- or die("ERROR: reading string\n");
-
- $length = unpack_int32($packed_word, $endianness);
- $pad = 4 - $length % 4;
-
- if ($length == 0)
- {
- return (1, undef);
- }
-
- read($handle, $string, $length) ==
- $length or die("ERROR: reading string\n");
- seek($handle, $pad, 1);
-
- return(1 + ($length + $pad) / 4, $string);
-}
-
-#
-# unpack_int32(word, endianess)
-#
-# Interpret 4-byte binary string WORD as signed 32 bit integer in
-# endian encoding defined by ENDIANNESS (0=little, 1=big) and return its
-# value.
-#
-
-sub unpack_int32($$)
-{
- return sprintf("%d", unpack($_[1] ? "N" : "V",$_[0]));
+ return(\@result, $branches, \@functions);
}
@@ -1585,10 +1691,11 @@
$result = $1 << 16 | $2 << 8;
}
}
- if ($version_string =~ /suse/i && $result == 0x30303)
+ if ($version_string =~ /suse/i && $result == 0x30303 ||
+ $version_string =~ /mandrake/i && $result == 0x30302)
{
- info("Using compatibility mode for SUSE GCC 3.3.3\n");
- $compatibility = $COMPAT_SLES9;
+ info("Using compatibility mode for GCC 3.3 (hammer)\n");
+ $compatibility = $COMPAT_HAMMER;
}
return $result;
}
@@ -1608,7 +1715,7 @@
# Print info string
if (defined($output_filename) && ($output_filename eq "-"))
{
- # Don't interfer with the .info output to STDOUT
+ # Don't interfere with the .info output to STDOUT
printf(STDERR @_);
}
else
@@ -1745,3 +1852,1221 @@
}
}
}
+
+
+#
+# get_exclusion_data(filename)
+#
+# Scan specified source code file for exclusion markers and return
+# linenumber -> 1
+# for all lines which should be excluded.
+#
+
+sub get_exclusion_data($)
+{
+ my ($filename) = @_;
+ my %list;
+ my $flag = 0;
+ local *HANDLE;
+
+ if (!open(HANDLE, "<$filename")) {
+ warn("WARNING: could not open $filename\n");
+ return undef;
+ }
+ while (<HANDLE>) {
+ if (/$EXCL_STOP/) {
+ $flag = 0;
+ } elsif (/$EXCL_START/) {
+ $flag = 1;
+ }
+ if (/$EXCL_LINE/ || $flag) {
+ $list{$.} = 1;
+ }
+ }
+ close(HANDLE);
+
+ if ($flag) {
+ warn("WARNING: unterminated exclusion section in $filename\n");
+ }
+
+ return \%list;
+}
+
+
+#
+# apply_exclusion_data(instr, graph)
+#
+# Remove lines from instr and graph data structures which are marked
+# for exclusion in the source code file.
+#
+# Return adjusted (instr, graph).
+#
+# graph : file name -> function data
+# function data : function name -> line data
+# line data : [ line1, line2, ... ]
+#
+# instr : filename -> line data
+# line data : [ line1, line2, ... ]
+#
+
+sub apply_exclusion_data($$)
+{
+ my ($instr, $graph) = @_;
+ my $filename;
+ my %excl_data;
+ my $excl_read_failed = 0;
+
+ # Collect exclusion marker data
+ foreach $filename (sort_uniq_lex(keys(%{$graph}), keys(%{$instr}))) {
+ my $excl = get_exclusion_data($filename);
+
+ # Skip and note if file could not be read
+ if (!defined($excl)) {
+ $excl_read_failed = 1;
+ next;
+ }
+
+ # Add to collection if there are markers
+ $excl_data{$filename} = $excl if (keys(%{$excl}) > 0);
+ }
+
+ # Warn if not all source files could be read
+ if ($excl_read_failed) {
+ warn("WARNING: some exclusion markers may be ignored\n");
+ }
+
+ # Skip if no markers were found
+ return ($instr, $graph) if (keys(%excl_data) == 0);
+
+ # Apply exclusion marker data to graph
+ foreach $filename (keys(%excl_data)) {
+ my $function_data = $graph->{$filename};
+ my $excl = $excl_data{$filename};
+ my $function;
+
+ next if (!defined($function_data));
+
+ foreach $function (keys(%{$function_data})) {
+ my $line_data = $function_data->{$function};
+ my $line;
+ my @new_data;
+
+ # To be consistent with exclusion parser in non-initial
+ # case we need to remove a function if the first line
+ # was excluded
+ if ($excl->{$line_data->[0]}) {
+ delete($function_data->{$function});
+ next;
+ }
+ # Copy only lines which are not excluded
+ foreach $line (@{$line_data}) {
+ push(@new_data, $line) if (!$excl->{$line});
+ }
+
+ # Store modified list
+ if (scalar(@new_data) > 0) {
+ $function_data->{$function} = \@new_data;
+ } else {
+ # All of this function was excluded
+ delete($function_data->{$function});
+ }
+ }
+
+ # Check if all functions of this file were excluded
+ if (keys(%{$function_data}) == 0) {
+ delete($graph->{$filename});
+ }
+ }
+
+ # Apply exclusion marker data to instr
+ foreach $filename (keys(%excl_data)) {
+ my $line_data = $instr->{$filename};
+ my $excl = $excl_data{$filename};
+ my $line;
+ my @new_data;
+
+ next if (!defined($line_data));
+
+ # Copy only lines which are not excluded
+ foreach $line (@{$line_data}) {
+ push(@new_data, $line) if (!$excl->{$line});
+ }
+
+ # Store modified list
+ if (scalar(@new_data) > 0) {
+ $instr->{$filename} = \@new_data;
+ } else {
+ # All of this file was excluded
+ delete($instr->{$filename});
+ }
+ }
+
+ return ($instr, $graph);
+}
+
+
+sub process_graphfile($$)
+{
+ my ($file, $dir) = @_;
+ my $graph_filename = $file;
+ my $graph_dir;
+ my $graph_basename;
+ my $source_dir;
+ my $base_dir;
+ my $graph;
+ my $instr;
+ my $filename;
+ local *INFO_HANDLE;
+
+ info("Processing %s\n", abs2rel($file, $dir));
+
+ # Get path to data file in absolute and normalized form (begins with /,
+ # contains no more ../ or ./)
+ $graph_filename = solve_relative_path($cwd, $graph_filename);
+
+ # Get directory and basename of data file
+ ($graph_dir, $graph_basename) = split_filename($graph_filename);
+
+ # avoid files from .libs dirs
+ if ($compat_libtool && $graph_dir =~ m/(.*)\/\.libs$/) {
+ $source_dir = $1;
+ } else {
+ $source_dir = $graph_dir;
+ }
+
+ # Construct base_dir for current file
+ if ($base_directory)
+ {
+ $base_dir = $base_directory;
+ }
+ else
+ {
+ $base_dir = $source_dir;
+ }
+
+ if ($gcov_version < $GCOV_VERSION_3_4_0)
+ {
+ if (defined($compatibility) && $compatibility eq $COMPAT_HAMMER)
+ {
+ ($instr, $graph) = read_bbg($graph_filename, $base_dir);
+ }
+ else
+ {
+ ($instr, $graph) = read_bb($graph_filename, $base_dir);
+ }
+ }
+ else
+ {
+ ($instr, $graph) = read_gcno($graph_filename, $base_dir);
+ }
+
+ if (!$no_markers) {
+ # Apply exclusion marker data to graph file data
+ ($instr, $graph) = apply_exclusion_data($instr, $graph);
+ }
+
+ # Check whether we're writing to a single file
+ if ($output_filename)
+ {
+ if ($output_filename eq "-")
+ {
+ *INFO_HANDLE = *STDOUT;
+ }
+ else
+ {
+ # Append to output file
+ open(INFO_HANDLE, ">>$output_filename")
+ or die("ERROR: cannot write to ".
+ "$output_filename!\n");
+ }
+ }
+ else
+ {
+ # Open .info file for output
+ open(INFO_HANDLE, ">$graph_filename.info")
+ or die("ERROR: cannot create $graph_filename.info!\n");
+ }
+
+ # Write test name
+ printf(INFO_HANDLE "TN:%s\n", $test_name);
+ foreach $filename (sort(keys(%{$instr})))
+ {
+ my $funcdata = $graph->{$filename};
+ my $line;
+ my $linedata;
+
+ print(INFO_HANDLE "SF:$filename\n");
+
+ if (defined($funcdata)) {
+ my @functions = sort {$funcdata->{$a}->[0] <=>
+ $funcdata->{$b}->[0]}
+ keys(%{$funcdata});
+ my $func;
+
+ # Gather list of instrumented lines and functions
+ foreach $func (@functions) {
+ $linedata = $funcdata->{$func};
+
+ # Print function name and starting line
+ print(INFO_HANDLE "FN:".$linedata->[0].
+ ",".filter_fn_name($func)."\n");
+ }
+ # Print zero function coverage data
+ foreach $func (@functions) {
+ print(INFO_HANDLE "FNDA:0,".
+ filter_fn_name($func)."\n");
+ }
+ # Print function summary
+ print(INFO_HANDLE "FNF:".scalar(@functions)."\n");
+ print(INFO_HANDLE "FNH:0\n");
+ }
+ # Print zero line coverage data
+ foreach $line (@{$instr->{$filename}}) {
+ print(INFO_HANDLE "DA:$line,0\n");
+ }
+ # Print line summary
+ print(INFO_HANDLE "LF:".scalar(@{$instr->{$filename}})."\n");
+ print(INFO_HANDLE "LH:0\n");
+
+ print(INFO_HANDLE "end_of_record\n");
+ }
+ if (!($output_filename && ($output_filename eq "-")))
+ {
+ close(INFO_HANDLE);
+ }
+}
+
+sub filter_fn_name($)
+{
+ my ($fn) = @_;
+
+ # Remove characters used internally as function name delimiters
+ $fn =~ s/[,=]/_/g;
+
+ return $fn;
+}
+
+sub warn_handler($)
+{
+ my ($msg) = @_;
+
+ warn("$tool_name: $msg");
+}
+
+sub die_handler($)
+{
+ my ($msg) = @_;
+
+ die("$tool_name: $msg");
+}
+
+
+#
+# graph_error(filename, message)
+#
+# Print message about error in graph file. If ignore_graph_error is set, return.
+# Otherwise abort.
+#
+
+sub graph_error($$)
+{
+ my ($filename, $msg) = @_;
+
+ if ($ignore[$ERROR_GRAPH]) {
+ warn("WARNING: $filename: $msg - skipping\n");
+ return;
+ }
+ die("ERROR: $filename: $msg\n");
+}
+
+#
+# graph_expect(description)
+#
+# If debug is set to a non-zero value, print the specified description of what
+# is expected to be read next from the graph file.
+#
+
+sub graph_expect($)
+{
+ my ($msg) = @_;
+
+ if (!$debug || !defined($msg)) {
+ return;
+ }
+
+ print(STDERR "DEBUG: expecting $msg\n");
+}
+
+#
+# graph_read(handle, bytes[, description])
+#
+# Read and return the specified number of bytes from handle. Return undef
+# if the number of bytes could not be read.
+#
+
+sub graph_read(*$;$)
+{
+ my ($handle, $length, $desc) = @_;
+ my $data;
+ my $result;
+
+ graph_expect($desc);
+ $result = read($handle, $data, $length);
+ if ($debug) {
+ my $ascii = "";
+ my $hex = "";
+ my $i;
+
+ print(STDERR "DEBUG: read($length)=$result: ");
+ for ($i = 0; $i < length($data); $i++) {
+ my $c = substr($data, $i, 1);;
+ my $n = ord($c);
+
+ $hex .= sprintf("%02x ", $n);
+ if ($n >= 32 && $n <= 127) {
+ $ascii .= $c;
+ } else {
+ $ascii .= ".";
+ }
+ }
+ print(STDERR "$hex |$ascii|");
+ print(STDERR "\n");
+ }
+ if ($result != $length) {
+ return undef;
+ }
+ return $data;
+}
+
+#
+# graph_skip(handle, bytes[, description])
+#
+# Read and discard the specified number of bytes from handle. Return non-zero
+# if bytes could be read, zero otherwise.
+#
+
+sub graph_skip(*$;$)
+{
+ my ($handle, $length, $desc) = @_;
+
+ if (defined(graph_read($handle, $length, $desc))) {
+ return 1;
+ }
+ return 0;
+}
+
+#
+# sort_uniq(list)
+#
+# Return list in numerically ascending order and without duplicate entries.
+#
+
+sub sort_uniq(@)
+{
+ my (@list) = @_;
+ my %hash;
+
+ foreach (@list) {
+ $hash{$_} = 1;
+ }
+ return sort { $a <=> $b } keys(%hash);
+}
+
+#
+# sort_uniq_lex(list)
+#
+# Return list in lexically ascending order and without duplicate entries.
+#
+
+sub sort_uniq_lex(@)
+{
+ my (@list) = @_;
+ my %hash;
+
+ foreach (@list) {
+ $hash{$_} = 1;
+ }
+ return sort keys(%hash);
+}
+
+#
+# graph_cleanup(graph)
+#
+# Remove entries for functions with no lines. Remove duplicate line numbers.
+# Sort list of line numbers numerically ascending.
+#
+
+sub graph_cleanup($)
+{
+ my ($graph) = @_;
+ my $filename;
+
+ foreach $filename (keys(%{$graph})) {
+ my $per_file = $graph->{$filename};
+ my $function;
+
+ foreach $function (keys(%{$per_file})) {
+ my $lines = $per_file->{$function};
+
+ if (scalar(@$lines) == 0) {
+ # Remove empty function
+ delete($per_file->{$function});
+ next;
+ }
+ # Normalize list
+ $per_file->{$function} = [ sort_uniq(@$lines) ];
+ }
+ if (scalar(keys(%{$per_file})) == 0) {
+ # Remove empty file
+ delete($graph->{$filename});
+ }
+ }
+}
+
+#
+# graph_find_base(bb)
+#
+# Try to identify the filename which is the base source file for the
+# specified bb data.
+#
+
+sub graph_find_base($)
+{
+ my ($bb) = @_;
+ my %file_count;
+ my $basefile;
+ my $file;
+ my $func;
+ my $filedata;
+ my $count;
+ my $num;
+
+ # Identify base name for this bb data.
+ foreach $func (keys(%{$bb})) {
+ $filedata = $bb->{$func};
+
+ foreach $file (keys(%{$filedata})) {
+ $count = $file_count{$file};
+
+ # Count file occurrence
+ $file_count{$file} = defined($count) ? $count + 1 : 1;
+ }
+ }
+ $count = 0;
+ $num = 0;
+ foreach $file (keys(%file_count)) {
+ if ($file_count{$file} > $count) {
+ # The file that contains code for the most functions
+ # is likely the base file
+ $count = $file_count{$file};
+ $num = 1;
+ $basefile = $file;
+ } elsif ($file_count{$file} == $count) {
+ # If more than one file could be the basefile, we
+ # don't have a basefile
+ $basefile = undef;
+ }
+ }
+
+ return $basefile;
+}
+
+#
+# graph_from_bb(bb, fileorder, bb_filename)
+#
+# Convert data from bb to the graph format and list of instrumented lines.
+# Returns (instr, graph).
+#
+# bb : function name -> file data
+# : undef -> file order
+# file data : filename -> line data
+# line data : [ line1, line2, ... ]
+#
+# file order : function name -> [ filename1, filename2, ... ]
+#
+# graph : file name -> function data
+# function data : function name -> line data
+# line data : [ line1, line2, ... ]
+#
+# instr : filename -> line data
+# line data : [ line1, line2, ... ]
+#
+
+sub graph_from_bb($$$)
+{
+ my ($bb, $fileorder, $bb_filename) = @_;
+ my $graph = {};
+ my $instr = {};
+ my $basefile;
+ my $file;
+ my $func;
+ my $filedata;
+ my $linedata;
+ my $order;
+
+ $basefile = graph_find_base($bb);
+ # Create graph structure
+ foreach $func (keys(%{$bb})) {
+ $filedata = $bb->{$func};
+ $order = $fileorder->{$func};
+
+ # Account for lines in functions
+ if (defined($basefile) && defined($filedata->{$basefile})) {
+ # If the basefile contributes to this function,
+ # account this function to the basefile.
+ $graph->{$basefile}->{$func} = $filedata->{$basefile};
+ } else {
+ # If the basefile does not contribute to this function,
+ # account this function to the first file contributing
+ # lines.
+ $graph->{$order->[0]}->{$func} =
+ $filedata->{$order->[0]};
+ }
+
+ foreach $file (keys(%{$filedata})) {
+ # Account for instrumented lines
+ $linedata = $filedata->{$file};
+ push(@{$instr->{$file}}, @$linedata);
+ }
+ }
+ # Clean up array of instrumented lines
+ foreach $file (keys(%{$instr})) {
+ $instr->{$file} = [ sort_uniq(@{$instr->{$file}}) ];
+ }
+
+ return ($instr, $graph);
+}
+
+#
+# graph_add_order(fileorder, function, filename)
+#
+# Add an entry for filename to the fileorder data set for function.
+#
+
+sub graph_add_order($$$)
+{
+ my ($fileorder, $function, $filename) = @_;
+ my $item;
+ my $list;
+
+ $list = $fileorder->{$function};
+ foreach $item (@$list) {
+ if ($item eq $filename) {
+ return;
+ }
+ }
+ push(@$list, $filename);
+ $fileorder->{$function} = $list;
+}
+#
+# read_bb_word(handle[, description])
+#
+# Read and return a word in .bb format from handle.
+#
+
+sub read_bb_word(*;$)
+{
+ my ($handle, $desc) = @_;
+
+ return graph_read($handle, 4, $desc);
+}
+
+#
+# read_bb_value(handle[, description])
+#
+# Read a word in .bb format from handle and return the word and its integer
+# value.
+#
+
+sub read_bb_value(*;$)
+{
+ my ($handle, $desc) = @_;
+ my $word;
+
+ $word = read_bb_word($handle, $desc);
+ return undef if (!defined($word));
+
+ return ($word, unpack("V", $word));
+}
+
+#
+# read_bb_string(handle, delimiter)
+#
+# Read and return a string in .bb format from handle up to the specified
+# delimiter value.
+#
+
+sub read_bb_string(*$)
+{
+ my ($handle, $delimiter) = @_;
+ my $word;
+ my $value;
+ my $string = "";
+
+ graph_expect("string");
+ do {
+ ($word, $value) = read_bb_value($handle, "string or delimiter");
+ return undef if (!defined($value));
+ if ($value != $delimiter) {
+ $string .= $word;
+ }
+ } while ($value != $delimiter);
+ $string =~ s/\0//g;
+
+ return $string;
+}
+
+#
+# read_bb(filename, base_dir)
+#
+# Read the contents of the specified .bb file and return (instr, graph), where:
+#
+# instr : filename -> line data
+# line data : [ line1, line2, ... ]
+#
+# graph : filename -> file_data
+# file_data : function name -> line_data
+# line_data : [ line1, line2, ... ]
+#
+# Relative filenames are converted to absolute form using base_dir as
+# base directory. See the gcov info pages of gcc 2.95 for a description of
+# the .bb file format.
+#
+
+sub read_bb($$)
+{
+ my ($bb_filename, $base) = @_;
+ my $minus_one = 0x80000001;
+ my $minus_two = 0x80000002;
+ my $value;
+ my $filename;
+ my $function;
+ my $bb = {};
+ my $fileorder = {};
+ my $instr;
+ my $graph;
+ local *HANDLE;
+
+ open(HANDLE, "<$bb_filename") or goto open_error;
+ binmode(HANDLE);
+ while (!eof(HANDLE)) {
+ $value = read_bb_value(*HANDLE, "data word");
+ goto incomplete if (!defined($value));
+ if ($value == $minus_one) {
+ # Source file name
+ graph_expect("filename");
+ $filename = read_bb_string(*HANDLE, $minus_one);
+ goto incomplete if (!defined($filename));
+ if ($filename ne "") {
+ $filename = solve_relative_path($base,
+ $filename);
+ }
+ } elsif ($value == $minus_two) {
+ # Function name
+ graph_expect("function name");
+ $function = read_bb_string(*HANDLE, $minus_two);
+ goto incomplete if (!defined($function));
+ } elsif ($value > 0) {
+ # Line number
+ if (!defined($filename) || !defined($function)) {
+ warn("WARNING: unassigned line number ".
+ "$value\n");
+ next;
+ }
+ push(@{$bb->{$function}->{$filename}}, $value);
+ graph_add_order($fileorder, $function, $filename);
+ }
+ }
+ close(HANDLE);
+ ($instr, $graph) = graph_from_bb($bb, $fileorder, $bb_filename);
+ graph_cleanup($graph);
+
+ return ($instr, $graph);
+
+open_error:
+ graph_error($bb_filename, "could not open file");
+ return undef;
+incomplete:
+ graph_error($bb_filename, "reached unexpected end of file");
+ return undef;
+}
+
+#
+# read_bbg_word(handle[, description])
+#
+# Read and return a word in .bbg format.
+#
+
+sub read_bbg_word(*;$)
+{
+ my ($handle, $desc) = @_;
+
+ return graph_read($handle, 4, $desc);
+}
+
+#
+# read_bbg_value(handle[, description])
+#
+# Read a word in .bbg format from handle and return its integer value.
+#
+
+sub read_bbg_value(*;$)
+{
+ my ($handle, $desc) = @_;
+ my $word;
+
+ $word = read_bbg_word($handle, $desc);
+ return undef if (!defined($word));
+
+ return unpack("N", $word);
+}
+
+#
+# read_bbg_string(handle)
+#
+# Read and return a string in .bbg format.
+#
+
+sub read_bbg_string(*)
+{
+ my ($handle, $desc) = @_;
+ my $length;
+ my $string;
+
+ graph_expect("string");
+ # Read string length
+ $length = read_bbg_value($handle, "string length");
+ return undef if (!defined($length));
+ if ($length == 0) {
+ return "";
+ }
+ # Read string
+ $string = graph_read($handle, $length, "string");
+ return undef if (!defined($string));
+ # Skip padding
+ graph_skip($handle, 4 - $length % 4, "string padding") or return undef;
+
+ return $string;
+}
+
+#
+# read_bbg_lines_record(handle, bbg_filename, bb, fileorder, filename,
+# function, base)
+#
+# Read a bbg format lines record from handle and add the relevant data to
+# bb and fileorder. Return filename on success, undef on error.
+#
+
+sub read_bbg_lines_record(*$$$$$$)
+{
+ my ($handle, $bbg_filename, $bb, $fileorder, $filename, $function,
+ $base) = @_;
+ my $string;
+ my $lineno;
+
+ graph_expect("lines record");
+ # Skip basic block index
+ graph_skip($handle, 4, "basic block index") or return undef;
+ while (1) {
+ # Read line number
+ $lineno = read_bbg_value($handle, "line number");
+ return undef if (!defined($lineno));
+ if ($lineno == 0) {
+ # Got a marker for a new filename
+ graph_expect("filename");
+ $string = read_bbg_string($handle);
+ return undef if (!defined($string));
+ # Check for end of record
+ if ($string eq "") {
+ return $filename;
+ }
+ $filename = solve_relative_path($base, $string);
+ next;
+ }
+ # Got an actual line number
+ if (!defined($filename)) {
+ warn("WARNING: unassigned line number in ".
+ "$bbg_filename\n");
+ next;
+ }
+ push(@{$bb->{$function}->{$filename}}, $lineno);
+ graph_add_order($fileorder, $function, $filename);
+ }
+}
+
+#
+# read_bbg(filename, base_dir)
+#
+# Read the contents of the specified .bbg file and return the following mapping:
+# graph: filename -> file_data
+# file_data: function name -> line_data
+# line_data: [ line1, line2, ... ]
+#
+# Relative filenames are converted to absolute form using base_dir as
+# base directory. See the gcov-io.h file in the SLES 9 gcc 3.3.3 source code
+# for a description of the .bbg format.
+#
+
+sub read_bbg($$)
+{
+ my ($bbg_filename, $base) = @_;
+ my $file_magic = 0x67626267;
+ my $tag_function = 0x01000000;
+ my $tag_lines = 0x01450000;
+ my $word;
+ my $tag;
+ my $length;
+ my $function;
+ my $filename;
+ my $bb = {};
+ my $fileorder = {};
+ my $instr;
+ my $graph;
+ local *HANDLE;
+
+ open(HANDLE, "<$bbg_filename") or goto open_error;
+ binmode(HANDLE);
+ # Read magic
+ $word = read_bbg_value(*HANDLE, "file magic");
+ goto incomplete if (!defined($word));
+ # Check magic
+ if ($word != $file_magic) {
+ goto magic_error;
+ }
+ # Skip version
+ graph_skip(*HANDLE, 4, "version") or goto incomplete;
+ while (!eof(HANDLE)) {
+ # Read record tag
+ $tag = read_bbg_value(*HANDLE, "record tag");
+ goto incomplete if (!defined($tag));
+ # Read record length
+ $length = read_bbg_value(*HANDLE, "record length");
+ goto incomplete if (!defined($tag));
+ if ($tag == $tag_function) {
+ graph_expect("function record");
+ # Read function name
+ graph_expect("function name");
+ $function = read_bbg_string(*HANDLE);
+ goto incomplete if (!defined($function));
+ $filename = undef;
+ # Skip function checksum
+ graph_skip(*HANDLE, 4, "function checksum")
+ or goto incomplete;
+ } elsif ($tag == $tag_lines) {
+ # Read lines record
+ $filename = read_bbg_lines_record(HANDLE, $bbg_filename,
+ $bb, $fileorder, $filename,
+ $function, $base);
+ goto incomplete if (!defined($filename));
+ } else {
+ # Skip record contents
+ graph_skip(*HANDLE, $length, "unhandled record")
+ or goto incomplete;
+ }
+ }
+ close(HANDLE);
+ ($instr, $graph) = graph_from_bb($bb, $fileorder, $bbg_filename);
+ graph_cleanup($graph);
+
+ return ($instr, $graph);
+
+open_error:
+ graph_error($bbg_filename, "could not open file");
+ return undef;
+incomplete:
+ graph_error($bbg_filename, "reached unexpected end of file");
+ return undef;
+magic_error:
+ graph_error($bbg_filename, "found unrecognized bbg file magic");
+ return undef;
+}
+
+#
+# read_gcno_word(handle[, description])
+#
+# Read and return a word in .gcno format.
+#
+
+sub read_gcno_word(*;$)
+{
+ my ($handle, $desc) = @_;
+
+ return graph_read($handle, 4, $desc);
+}
+
+#
+# read_gcno_value(handle, big_endian[, description])
+#
+# Read a word in .gcno format from handle and return its integer value
+# according to the specified endianness.
+#
+
+sub read_gcno_value(*$;$)
+{
+ my ($handle, $big_endian, $desc) = @_;
+ my $word;
+
+ $word = read_gcno_word($handle, $desc);
+ return undef if (!defined($word));
+ if ($big_endian) {
+ return unpack("N", $word);
+ } else {
+ return unpack("V", $word);
+ }
+}
+
+#
+# read_gcno_string(handle, big_endian)
+#
+# Read and return a string in .gcno format.
+#
+
+sub read_gcno_string(*$)
+{
+ my ($handle, $big_endian) = @_;
+ my $length;
+ my $string;
+
+ graph_expect("string");
+ # Read string length
+ $length = read_gcno_value($handle, $big_endian, "string length");
+ return undef if (!defined($length));
+ if ($length == 0) {
+ return "";
+ }
+ $length *= 4;
+ # Read string
+ $string = graph_read($handle, $length, "string and padding");
+ return undef if (!defined($string));
+ $string =~ s/\0//g;
+
+ return $string;
+}
+
+#
+# read_gcno_lines_record(handle, gcno_filename, bb, fileorder, filename,
+# function, base, big_endian)
+#
+# Read a gcno format lines record from handle and add the relevant data to
+# bb and fileorder. Return filename on success, undef on error.
+#
+
+sub read_gcno_lines_record(*$$$$$$$)
+{
+ my ($handle, $gcno_filename, $bb, $fileorder, $filename, $function,
+ $base, $big_endian) = @_;
+ my $string;
+ my $lineno;
+
+ graph_expect("lines record");
+ # Skip basic block index
+ graph_skip($handle, 4, "basic block index") or return undef;
+ while (1) {
+ # Read line number
+ $lineno = read_gcno_value($handle, $big_endian, "line number");
+ return undef if (!defined($lineno));
+ if ($lineno == 0) {
+ # Got a marker for a new filename
+ graph_expect("filename");
+ $string = read_gcno_string($handle, $big_endian);
+ return undef if (!defined($string));
+ # Check for end of record
+ if ($string eq "") {
+ return $filename;
+ }
+ $filename = solve_relative_path($base, $string);
+ next;
+ }
+ # Got an actual line number
+ if (!defined($filename)) {
+ warn("WARNING: unassigned line number in ".
+ "$gcno_filename\n");
+ next;
+ }
+ # Add to list
+ push(@{$bb->{$function}->{$filename}}, $lineno);
+ graph_add_order($fileorder, $function, $filename);
+ }
+}
+
+#
+# read_gcno_function_record(handle, graph, base, big_endian)
+#
+# Read a gcno format function record from handle and add the relevant data
+# to graph. Return (filename, function) on success, undef on error.
+#
+
+sub read_gcno_function_record(*$$$$)
+{
+ my ($handle, $bb, $fileorder, $base, $big_endian) = @_;
+ my $filename;
+ my $function;
+ my $lineno;
+ my $lines;
+
+ graph_expect("function record");
+ # Skip ident and checksum
+ graph_skip($handle, 8, "function ident and checksum") or return undef;
+ # Read function name
+ graph_expect("function name");
+ $function = read_gcno_string($handle, $big_endian);
+ return undef if (!defined($function));
+ # Read filename
+ graph_expect("filename");
+ $filename = read_gcno_string($handle, $big_endian);
+ return undef if (!defined($filename));
+ $filename = solve_relative_path($base, $filename);
+ # Read first line number
+ $lineno = read_gcno_value($handle, $big_endian, "initial line number");
+ return undef if (!defined($lineno));
+ # Add to list
+ push(@{$bb->{$function}->{$filename}}, $lineno);
+ graph_add_order($fileorder, $function, $filename);
+
+ return ($filename, $function);
+}
+
+#
+# read_gcno(filename, base_dir)
+#
+# Read the contents of the specified .gcno file and return the following
+# mapping:
+# graph: filename -> file_data
+# file_data: function name -> line_data
+# line_data: [ line1, line2, ... ]
+#
+# Relative filenames are converted to absolute form using base_dir as
+# base directory. See the gcov-io.h file in the gcc 3.3 source code
+# for a description of the .gcno format.
+#
+
+sub read_gcno($$)
+{
+ my ($gcno_filename, $base) = @_;
+ my $file_magic = 0x67636e6f;
+ my $tag_function = 0x01000000;
+ my $tag_lines = 0x01450000;
+ my $big_endian;
+ my $word;
+ my $tag;
+ my $length;
+ my $filename;
+ my $function;
+ my $bb = {};
+ my $fileorder = {};
+ my $instr;
+ my $graph;
+ local *HANDLE;
+
+ open(HANDLE, "<$gcno_filename") or goto open_error;
+ binmode(HANDLE);
+ # Read magic
+ $word = read_gcno_word(*HANDLE, "file magic");
+ goto incomplete if (!defined($word));
+ # Determine file endianness
+ if (unpack("N", $word) == $file_magic) {
+ $big_endian = 1;
+ } elsif (unpack("V", $word) == $file_magic) {
+ $big_endian = 0;
+ } else {
+ goto magic_error;
+ }
+ # Skip version and stamp
+ graph_skip(*HANDLE, 8, "version and stamp") or goto incomplete;
+ while (!eof(HANDLE)) {
+ my $next_pos;
+ my $curr_pos;
+
+ # Read record tag
+ $tag = read_gcno_value(*HANDLE, $big_endian, "record tag");
+ goto incomplete if (!defined($tag));
+ # Read record length
+ $length = read_gcno_value(*HANDLE, $big_endian,
+ "record length");
+ goto incomplete if (!defined($length));
+ # Convert length to bytes
+ $length *= 4;
+ # Calculate start of next record
+ $next_pos = tell(HANDLE);
+ goto tell_error if ($next_pos == -1);
+ $next_pos += $length;
+ # Process record
+ if ($tag == $tag_function) {
+ ($filename, $function) = read_gcno_function_record(
+ *HANDLE, $bb, $fileorder, $base, $big_endian);
+ goto incomplete if (!defined($function));
+ } elsif ($tag == $tag_lines) {
+ # Read lines record
+ $filename = read_gcno_lines_record(*HANDLE,
+ $gcno_filename, $bb, $fileorder,
+ $filename, $function, $base,
+ $big_endian);
+ goto incomplete if (!defined($filename));
+ } else {
+ # Skip record contents
+ graph_skip(*HANDLE, $length, "unhandled record")
+ or goto incomplete;
+ }
+ # Ensure that we are at the start of the next record
+ $curr_pos = tell(HANDLE);
+ goto tell_error if ($curr_pos == -1);
+ next if ($curr_pos == $next_pos);
+ goto record_error if ($curr_pos > $next_pos);
+ graph_skip(*HANDLE, $next_pos - $curr_pos,
+ "unhandled record content")
+ or goto incomplete;
+ }
+ close(HANDLE);
+ ($instr, $graph) = graph_from_bb($bb, $fileorder, $gcno_filename);
+ graph_cleanup($graph);
+
+ return ($instr, $graph);
+
+open_error:
+ graph_error($gcno_filename, "could not open file");
+ return undef;
+incomplete:
+ graph_error($gcno_filename, "reached unexpected end of file");
+ return undef;
+magic_error:
+ graph_error($gcno_filename, "found unrecognized gcno file magic");
+ return undef;
+tell_error:
+ graph_error($gcno_filename, "could not determine file position");
+ return undef;
+record_error:
+ graph_error($gcno_filename, "found unrecognized record format");
+ return undef;
+}
+
+sub debug($)
+{
+ my ($msg) = @_;
+
+ return if (!$debug);
+ print(STDERR "DEBUG: $msg");
+}
+
+#
+# get_gcov_capabilities
+#
+# Determine the list of available gcov options.
+#
+
+sub get_gcov_capabilities()
+{
+ my $help = `$gcov_tool --help`;
+ my %capabilities;
+
+ foreach (split(/\n/, $help)) {
+ next if (!/--(\S+)/);
+ next if ($1 eq 'help');
+ next if ($1 eq 'version');
+ next if ($1 eq 'object-directory');
+
+ $capabilities{$1} = 1;
+ debug("gcov has capability '$1'\n");
+ }
+
+ return \%capabilities;
+}
--- a/utils/lcov/lcov Sat Aug 20 14:41:19 2011 -0400
+++ b/utils/lcov/lcov Mon Oct 17 16:59:17 2011 -0400
@@ -1,6 +1,6 @@
#!/usr/bin/perl -w
#
-# Copyright (c) International Business Machines Corp., 2002
+# Copyright (c) International Business Machines Corp., 2002,2010
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -56,38 +56,47 @@
# modprobe before insmod (needed for 2.6)
# 2004-03-30 / Peter Oberparleiter: added --path option
# 2004-08-09 / Peter Oberparleiter: added configuration file support
+# 2008-08-13 / Peter Oberparleiter: added function coverage support
#
use strict;
-use File::Basename;
+use File::Basename;
+use File::Path;
+use File::Find;
+use File::Temp qw /tempdir/;
+use File::Spec::Functions qw /abs2rel canonpath catdir catfile catpath
+ file_name_is_absolute rootdir splitdir splitpath/;
use Getopt::Long;
+use Cwd qw /abs_path getcwd/;
# Global constants
-our $lcov_version = "LTP GCOV extension version 1.4";
+our $lcov_version = 'LCOV version 1.9';
our $lcov_url = "http://ltp.sourceforge.net/coverage/lcov.php";
-
-# Names of the GCOV kernel module
-our @gcovmod = ("gcov-prof", "gcov-proc");
+our $tool_name = basename($0);
# Directory containing gcov kernel files
-our $gcov_dir = "/proc/gcov";
-
-# The location of the insmod tool
-our $insmod_tool = "/sbin/insmod";
-
-# The location of the modprobe tool
-our $modprobe_tool = "/sbin/modprobe";
-
-# The location of the rmmod tool
-our $rmmod_tool = "/sbin/rmmod";
+our $gcov_dir;
# Where to create temporary directories
-our $tmp_dir = "/tmp";
-
-# How to prefix a temporary directory name
-our $tmp_prefix = "tmpdir";
-
+our $tmp_dir;
+
+# Internal constants
+our $GKV_PROC = 0; # gcov-kernel data in /proc via external patch
+our $GKV_SYS = 1; # gcov-kernel data in /sys via vanilla 2.6.31+
+our @GKV_NAME = ( "external", "upstream" );
+our $pkg_gkv_file = ".gcov_kernel_version";
+our $pkg_build_file = ".build_directory";
+
+our $BR_BLOCK = 0;
+our $BR_BRANCH = 1;
+our $BR_TAKEN = 2;
+our $BR_VEC_ENTRIES = 3;
+our $BR_VEC_WIDTH = 32;
+
+# Branch data combination types
+our $BR_SUB = 0;
+our $BR_ADD = 1;
# Prototypes
sub print_usage(*);
@@ -96,10 +105,12 @@
sub userspace_capture();
sub kernel_reset();
sub kernel_capture();
+sub kernel_capture_initial();
+sub package_capture();
sub add_traces();
sub read_info_file($);
sub get_info_entry($);
-sub set_info_entry($$$$$;$$);
+sub set_info_entry($$$$$$$$$;$$$$$$);
sub add_counts($$);
sub merge_checksums($$$);
sub combine_info_entries($$$);
@@ -114,13 +125,20 @@
sub system_no_output($@);
sub read_config($);
sub apply_config($);
-
sub info(@);
-sub unload_module($);
-sub check_and_load_kernel_module();
sub create_temp_dir();
sub transform_pattern($);
-
+sub warn_handler($);
+sub die_handler($);
+sub abort_handler($);
+sub temp_cleanup();
+sub setup_gkv();
+sub get_overall_line($$$$);
+sub print_overall_rate($$$$$$$$$);
+sub lcov_geninfo(@);
+sub create_package($$$;$);
+sub get_func_found_and_hit($);
+sub br_ivec_get($$);
# Global variables & initialization
our @directory; # Specifies where to get coverage data from
@@ -134,28 +152,60 @@
our $capture; # If set, capture data
our $output_filename; # Name for file to write coverage data to
our $test_name = ""; # Test case name
-our $source_dirs = "";
our $quiet = ""; # If set, suppress information messages
our $help; # Help option flag
our $version; # Version option flag
-our $nochecksum =""; # If set, don't calculate a checksum for each line
our $convert_filenames; # If set, convert filenames when applying diff
our $strip; # If set, strip leading directories when applying diff
-our $need_unload; # If set, unload gcov kernel module
our $temp_dir_name; # Name of temporary directory
our $cwd = `pwd`; # Current working directory
our $to_file; # If set, indicates that output is written to a file
our $follow; # If set, indicates that find shall follow links
our $diff_path = ""; # Path removed from tracefile when applying diff
+our $base_directory; # Base directory (cwd of gcc during compilation)
+our $checksum; # If set, calculate a checksum for each line
+our $no_checksum; # If set, don't calculate a checksum for each line
+our $compat_libtool; # If set, indicates that libtool mode is to be enabled
+our $no_compat_libtool; # If set, indicates that libtool mode is to be disabled
+our $gcov_tool;
+our $ignore_errors;
+our $initial;
+our $no_recursion = 0;
+our $to_package;
+our $from_package;
+our $maxdepth;
+our $no_markers;
our $config; # Configuration file contents
chomp($cwd);
our $tool_dir = dirname($0); # Directory where genhtml tool is installed
+our @temp_dirs;
+our $gcov_gkv; # gcov kernel support version found on machine
+our $opt_derive_func_data;
+our $opt_debug;
+our $opt_list_full_path;
+our $opt_no_list_full_path;
+our $opt_list_width = 80;
+our $opt_list_truncate_max = 20;
+our $ln_overall_found;
+our $ln_overall_hit;
+our $fn_overall_found;
+our $fn_overall_hit;
+our $br_overall_found;
+our $br_overall_hit;
#
# Code entry point
#
+$SIG{__WARN__} = \&warn_handler;
+$SIG{__DIE__} = \&die_handler;
+$SIG{'INT'} = \&abort_handler;
+$SIG{'QUIT'} = \&abort_handler;
+
+# Prettify version string
+$lcov_version =~ s/\$\s*Revision\s*:?\s*(\S+)\s*\$/$1/;
+
# Add current working directory if $tool_dir is not already an absolute path
if (! ($tool_dir =~ /^\/(.*)$/))
{
@@ -163,7 +213,7 @@
}
# Read configuration file if available
-if (-r $ENV{"HOME"}."/.lcovrc")
+if (defined($ENV{"HOME"}) && (-r $ENV{"HOME"}."/.lcovrc"))
{
$config = read_config($ENV{"HOME"}."/.lcovrc");
}
@@ -177,38 +227,74 @@
# Copy configuration file values to variables
apply_config({
"lcov_gcov_dir" => \$gcov_dir,
- "lcov_insmod_tool" => \$insmod_tool,
- "lcov_modprobe_tool" => \$modprobe_tool,
- "lcov_rmmod_tool" => \$rmmod_tool,
- "lcov_tmp_dir" => \$tmp_dir});
+ "lcov_tmp_dir" => \$tmp_dir,
+ "lcov_list_full_path" => \$opt_list_full_path,
+ "lcov_list_width" => \$opt_list_width,
+ "lcov_list_truncate_max"=> \$opt_list_truncate_max,
+ });
}
# Parse command line options
if (!GetOptions("directory|d|di=s" => \@directory,
- "add-tracefile=s" => \@add_tracefile,
- "list=s" => \$list,
- "kernel-directory=s" => \@kernel_directory,
- "extract=s" => \$extract,
- "remove=s" => \$remove,
+ "add-tracefile|a=s" => \@add_tracefile,
+ "list|l=s" => \$list,
+ "kernel-directory|k=s" => \@kernel_directory,
+ "extract|e=s" => \$extract,
+ "remove|r=s" => \$remove,
"diff=s" => \$diff,
- "no-checksum" => \$nochecksum,
"convert-filenames" => \$convert_filenames,
"strip=i" => \$strip,
"capture|c" => \$capture,
- "output-file=s" => \$output_filename,
- "test-name=s" => \$test_name,
- "source-dirs=s" => \$source_dirs,
- "zerocounters" => \$reset,
- "quiet" => \$quiet,
- "help" => \$help,
- "version" => \$version,
- "follow" => \$follow,
- "path=s" => \$diff_path
+ "output-file|o=s" => \$output_filename,
+ "test-name|t=s" => \$test_name,
+ "zerocounters|z" => \$reset,
+ "quiet|q" => \$quiet,
+ "help|h|?" => \$help,
+ "version|v" => \$version,
+ "follow|f" => \$follow,
+ "path=s" => \$diff_path,
+ "base-directory|b=s" => \$base_directory,
+ "checksum" => \$checksum,
+ "no-checksum" => \$no_checksum,
+ "compat-libtool" => \$compat_libtool,
+ "no-compat-libtool" => \$no_compat_libtool,
+ "gcov-tool=s" => \$gcov_tool,
+ "ignore-errors=s" => \$ignore_errors,
+ "initial|i" => \$initial,
+ "no-recursion" => \$no_recursion,
+ "to-package=s" => \$to_package,
+ "from-package=s" => \$from_package,
+ "no-markers" => \$no_markers,
+ "derive-func-data" => \$opt_derive_func_data,
+ "debug" => \$opt_debug,
+ "list-full-path" => \$opt_list_full_path,
+ "no-list-full-path" => \$opt_no_list_full_path,
))
{
- print_usage(*STDERR);
+ print(STDERR "Use $tool_name --help to get usage information\n");
exit(1);
}
+else
+{
+ # Merge options
+ if (defined($no_checksum))
+ {
+ $checksum = ($no_checksum ? 0 : 1);
+ $no_checksum = undef;
+ }
+
+ if (defined($no_compat_libtool))
+ {
+ $compat_libtool = ($no_compat_libtool ? 0 : 1);
+ $no_compat_libtool = undef;
+ }
+
+ if (defined($opt_no_list_full_path))
+ {
+ $opt_list_full_path = ($opt_no_list_full_path ? 0 : 1);
+ $opt_no_list_full_path = undef;
+ }
+}
# Check for help option
if ($help)
@@ -220,21 +306,45 @@
# Check for version option
if ($version)
{
- print("$lcov_version\n");
+ print("$tool_name: $lcov_version\n");
exit(0);
}
+# Check list width option
+if ($opt_list_width <= 40) {
+ die("ERROR: lcov_list_width parameter out of range (needs to be ".
+ "larger than 40)\n");
+}
+
# Normalize --path text
$diff_path =~ s/\/$//;
+if ($follow)
+{
+ $follow = "-follow";
+}
+else
+{
+ $follow = "";
+}
+
+if ($no_recursion)
+{
+ $maxdepth = "-maxdepth 1";
+}
+else
+{
+ $maxdepth = "";
+}
+
# Check for valid options
check_options();
# Only --extract, --remove and --diff allow unnamed parameters
if (@ARGV && !($extract || $remove || $diff))
{
- print_usage(*STDERR);
- exit(1);
+ die("Extra parameter found: '".join(" ", @ARGV)."'\n".
+ "Use $tool_name --help to get usage information\n");
}
# Check for output filename
@@ -249,6 +359,11 @@
}
}
+# Determine kernel directory for gcov data
+if (!$from_package && !@directory && ($capture || $reset)) {
+ ($gcov_gkv, $gcov_dir) = setup_gkv();
+}
+
# Check for requested functionality
if ($reset)
{
@@ -264,27 +379,40 @@
}
elsif ($capture)
{
- # Differentiate between user space and kernel
- if (@directory)
- {
+ # Capture source can be user space, kernel or package
+ if ($from_package) {
+ package_capture();
+ } elsif (@directory) {
userspace_capture();
- }
- else
- {
- kernel_capture();
+ } else {
+ if ($initial) {
+ if (defined($to_package)) {
+ die("ERROR: --initial cannot be used together ".
+ "with --to-package\n");
+ }
+ kernel_capture_initial();
+ } else {
+ kernel_capture();
+ }
}
}
elsif (@add_tracefile)
{
- add_traces();
+ ($ln_overall_found, $ln_overall_hit,
+ $fn_overall_found, $fn_overall_hit,
+ $br_overall_found, $br_overall_hit) = add_traces();
}
elsif ($remove)
{
- remove();
+ ($ln_overall_found, $ln_overall_hit,
+ $fn_overall_found, $fn_overall_hit,
+ $br_overall_found, $br_overall_hit) = remove();
}
elsif ($extract)
{
- extract();
+ ($ln_overall_found, $ln_overall_hit,
+ $fn_overall_found, $fn_overall_hit,
+ $br_overall_found, $br_overall_hit) = extract();
}
elsif ($list)
{
@@ -294,20 +422,25 @@
{
if (scalar(@ARGV) != 1)
{
- die("ERROR: option --diff requires one additional argument!\n");
+ die("ERROR: option --diff requires one additional argument!\n".
+ "Use $tool_name --help to get usage information\n");
}
- diff();
+ ($ln_overall_found, $ln_overall_hit,
+ $fn_overall_found, $fn_overall_hit,
+ $br_overall_found, $br_overall_hit) = diff();
}
-info("Done.\n");
+temp_cleanup();
+
+if (defined($ln_overall_found)) {
+ print_overall_rate(1, $ln_overall_found, $ln_overall_hit,
+ 1, $fn_overall_found, $fn_overall_hit,
+ 1, $br_overall_found, $br_overall_hit);
+} else {
+ info("Done.\n") if (!$list && !$capture);
+}
exit(0);
-# Check for follow option
-if ($follow)
-{
- $follow = "--follow";
-}
-
#
# print_usage(handle)
#
@@ -317,7 +450,6 @@
sub print_usage(*)
{
local *HANDLE = $_[0];
- my $tool_name = basename($0);
print(HANDLE <<END_OF_USAGE);
Usage: $tool_name [OPTIONS]
@@ -326,27 +458,43 @@
kernel or from a user space application. Specify the --directory option to
get coverage data for a user space program.
+Misc:
-h, --help Print this help, then exit
-v, --version Print version number, then exit
-q, --quiet Do not print progress messages
+
+Operation:
-z, --zerocounters Reset all execution counts to zero
-c, --capture Capture coverage data
- -t, --test-name NAME Specify test name to be stored with data
- -o, --output-file FILENAME Write data to FILENAME instead of stdout
- -d, --directory DIR Use .da/.gcda files in DIR instead of kernel
- -f, --follow Follow links when searching .da/.gcda files
- -k, --kernel-directory KDIR Capture kernel coverage data only from KDIR
-a, --add-tracefile FILE Add contents of tracefiles
-e, --extract FILE PATTERN Extract files matching PATTERN from FILE
-r, --remove FILE PATTERN Remove files matching PATTERN from FILE
-l, --list FILE List contents of tracefile FILE
--diff FILE DIFF Transform tracefile FILE according to DIFF
- --no-checksum Do not calculate a checksum for each line
+
+Options:
+ -i, --initial Capture initial zero coverage data
+ -t, --test-name NAME Specify test name to be stored with data
+ -o, --output-file FILENAME Write data to FILENAME instead of stdout
+ -d, --directory DIR Use .da files in DIR instead of kernel
+ -f, --follow Follow links when searching .da files
+ -k, --kernel-directory KDIR Capture kernel coverage data only from KDIR
+ -b, --base-directory DIR Use DIR as base directory for relative paths
--convert-filenames Convert filenames when applying diff
--strip DEPTH Strip initial DEPTH directory levels in diff
--path PATH Strip PATH from tracefile when applying diff
-
-See $lcov_url for more information about this tool.
+ --(no-)checksum Enable (disable) line checksumming
+ --(no-)compat-libtool Enable (disable) libtool compatibility mode
+ --gcov-tool TOOL Specify gcov tool location
+ --ignore-errors ERRORS Continue after ERRORS (gcov, source, graph)
+ --no-recursion Exclude subdirectories from processing
+ --to-package FILENAME Store unprocessed coverage data in FILENAME
+ --from-package FILENAME Capture from unprocessed data in FILENAME
+ --no-markers Ignore exclusion markers in source code
+ --derive-func-data Generate function data from line data
+ --list-full-path Print full path during a list operation
+
+For more information see: $lcov_url
END_OF_USAGE
;
}
@@ -373,15 +521,15 @@
if ($i == 0)
{
- print(STDERR "Need one of the options -z, -c, -e, -a, -r, -l ".
- "or --diff\n");
- print_usage(*STDERR);
- exit(2);
+ die("Need one of the options -z, -c, -a, -e, -r, -l or ".
+ "--diff\n".
+ "Use $tool_name --help to get usage information\n");
}
elsif ($i > 1)
{
- die("ERROR: only one of -z, -c, -e, -a, -r, -l or ".
- "--diff allowed!\n");
+ die("ERROR: only one of -z, -c, -a, -e, -r, -l or ".
+ "--diff allowed!\n".
+ "Use $tool_name --help to get usage information\n");
}
}
@@ -401,18 +549,9 @@
foreach $current_dir (@directory)
{
- info("Deleting all .da and .gcda files in $current_dir and ".
- "subdirectories\n");
- if ($follow)
- {
- @file_list =
- `find $current_dir -follow \\( -name \\*.gcda -o -name \\*.da \\) -type f 2>/dev/null`;
- }
- else
- {
- @file_list =
- `find $current_dir \\( -name \\*.gcda -o -name \\*.da \\) -type f 2>/dev/null`;
- }
+ info("Deleting all .da files in $current_dir".
+ ($no_recursion?"\n":" and subdirectories\n"));
+ @file_list = `find "$current_dir" $maxdepth $follow -name \\*\\.da -o -name \\*\\.gcda -type f 2>/dev/null`;
chomp(@file_list);
foreach (@file_list)
{
@@ -425,19 +564,197 @@
#
# userspace_capture()
#
-# Capture coverage data found in DIRECTORY and write it to OUTPUT_FILENAME
-# if specified, otherwise to STDOUT.
+# Capture coverage data found in DIRECTORY and write it to a package (if
+# TO_PACKAGE specified) or to OUTPUT_FILENAME or STDOUT.
#
# Die on error.
#
sub userspace_capture()
{
+ my $dir;
+ my $build;
+
+ if (!defined($to_package)) {
+ lcov_geninfo(@directory);
+ return;
+ }
+ if (scalar(@directory) != 1) {
+ die("ERROR: -d may be specified only once with --to-package\n");
+ }
+ $dir = $directory[0];
+ if (defined($base_directory)) {
+ $build = $base_directory;
+ } else {
+ $build = $dir;
+ }
+ create_package($to_package, $dir, $build);
+}
+
+
+#
+# kernel_reset()
+#
+# Reset kernel coverage.
+#
+# Die on error.
+#
+
+sub kernel_reset()
+{
+ local *HANDLE;
+ my $reset_file;
+
+ info("Resetting kernel execution counters\n");
+ if (-e "$gcov_dir/vmlinux") {
+ $reset_file = "$gcov_dir/vmlinux";
+ } elsif (-e "$gcov_dir/reset") {
+ $reset_file = "$gcov_dir/reset";
+ } else {
+ die("ERROR: no reset control found in $gcov_dir\n");
+ }
+ open(HANDLE, ">$reset_file") or
+ die("ERROR: cannot write to $reset_file!\n");
+ print(HANDLE "0");
+ close(HANDLE);
+}
+
+
+#
+# lcov_copy_single(from, to)
+#
+# Copy single regular file FROM to TO without checking its size. This is
+# required to work with special files generated by the kernel
+# seq_file-interface.
+#
+#
+sub lcov_copy_single($$)
+{
+ my ($from, $to) = @_;
+ my $content;
+ local $/;
+ local *HANDLE;
+
+ open(HANDLE, "<$from") or die("ERROR: cannot read $from: $!\n");
+ $content = <HANDLE>;
+ close(HANDLE);
+ open(HANDLE, ">$to") or die("ERROR: cannot write $from: $!\n");
+ if (defined($content)) {
+ print(HANDLE $content);
+ }
+ close(HANDLE);
+}
+
+#
+# lcov_find(dir, function, data[, extension, ...)])
+#
+# Search DIR for files and directories whose name matches PATTERN and run
+# FUNCTION for each match. If not pattern is specified, match all names.
+#
+# FUNCTION has the following prototype:
+# function(dir, relative_name, data)
+#
+# Where:
+# dir: the base directory for this search
+# relative_name: the name relative to the base directory of this entry
+# data: the DATA variable passed to lcov_find
+#
+sub lcov_find($$$;@)
+{
+ my ($dir, $fn, $data, @pattern) = @_;
+ my $result;
+ my $_fn = sub {
+ my $filename = $File::Find::name;
+
+ if (defined($result)) {
+ return;
+ }
+ $filename = abs2rel($filename, $dir);
+ foreach (@pattern) {
+ if ($filename =~ /$_/) {
+ goto ok;
+ }
+ }
+ return;
+ ok:
+ $result = &$fn($dir, $filename, $data);
+ };
+ if (scalar(@pattern) == 0) {
+ @pattern = ".*";
+ }
+ find( { wanted => $_fn, no_chdir => 1 }, $dir);
+
+ return $result;
+}
+
+#
+# lcov_copy_fn(from, rel, to)
+#
+# Copy directories, files and links from/rel to to/rel.
+#
+
+sub lcov_copy_fn($$$)
+{
+ my ($from, $rel, $to) = @_;
+ my $absfrom = canonpath(catfile($from, $rel));
+ my $absto = canonpath(catfile($to, $rel));
+
+ if (-d) {
+ if (! -d $absto) {
+ mkpath($absto) or
+ die("ERROR: cannot create directory $absto\n");
+ chmod(0700, $absto);
+ }
+ } elsif (-l) {
+ # Copy symbolic link
+ my $link = readlink($absfrom);
+
+ if (!defined($link)) {
+ die("ERROR: cannot read link $absfrom: $!\n");
+ }
+ symlink($link, $absto) or
+ die("ERROR: cannot create link $absto: $!\n");
+ } else {
+ lcov_copy_single($absfrom, $absto);
+ chmod(0600, $absto);
+ }
+ return undef;
+}
+
+#
+# lcov_copy(from, to, subdirs)
+#
+# Copy all specified SUBDIRS and files from directory FROM to directory TO. For
+# regular files, copy file contents without checking its size. This is required
+# to work with seq_file-generated files.
+#
+
+sub lcov_copy($$;@)
+{
+ my ($from, $to, @subdirs) = @_;
+ my @pattern;
+
+ foreach (@subdirs) {
+ push(@pattern, "^$_");
+ }
+ lcov_find($from, \&lcov_copy_fn, $to, @pattern);
+}
+
+#
+# lcov_geninfo(directory)
+#
+# Call geninfo for the specified directory and with the parameters specified
+# at the command line.
+#
+
+sub lcov_geninfo(@)
+{
+ my (@dir) = @_;
my @param;
- my $file_list = join(" ", @directory);
-
- info("Capturing coverage data from $file_list\n");
- @param = ("$tool_dir/geninfo", @directory);
+
+ # Capture data
+ info("Capturing coverage data from ".join(" ", @dir)."\n");
+ @param = ("$tool_dir/geninfo", @dir);
if ($output_filename)
{
@param = (@param, "--output-filename", $output_filename);
@@ -454,142 +771,478 @@
{
@param = (@param, "--quiet");
}
- if ($nochecksum)
+ if (defined($checksum))
+ {
+ if ($checksum)
+ {
+ @param = (@param, "--checksum");
+ }
+ else
+ {
+ @param = (@param, "--no-checksum");
+ }
+ }
+ if ($base_directory)
+ {
+ @param = (@param, "--base-directory", $base_directory);
+ }
+ if ($no_compat_libtool)
+ {
+ @param = (@param, "--no-compat-libtool");
+ }
+ elsif ($compat_libtool)
{
- @param = (@param, "--no-checksum");
+ @param = (@param, "--compat-libtool");
+ }
+ if ($gcov_tool)
+ {
+ @param = (@param, "--gcov-tool", $gcov_tool);
+ }
+ if ($ignore_errors)
+ {
+ @param = (@param, "--ignore-errors", $ignore_errors);
+ }
+ if ($initial)
+ {
+ @param = (@param, "--initial");
+ }
+ if ($no_markers)
+ {
+ @param = (@param, "--no-markers");
+ }
+ if ($opt_derive_func_data)
+ {
+ @param = (@param, "--derive-func-data");
+ }
+ if ($opt_debug)
+ {
+ @param = (@param, "--debug");
}
- @param = (@param, "--source-dirs", $source_dirs);
-
- system(@param);
- exit($? >> 8);
+ system(@param) and exit($? >> 8);
+}
+
+#
+# read_file(filename)
+#
+# Return the contents of the file defined by filename.
+#
+
+sub read_file($)
+{
+ my ($filename) = @_;
+ my $content;
+ local $\;
+ local *HANDLE;
+
+ open(HANDLE, "<$filename") || return undef;
+ $content = <HANDLE>;
+ close(HANDLE);
+
+ return $content;
+}
+
+#
+# get_package(package_file)
+#
+# Unpack unprocessed coverage data files from package_file to a temporary
+# directory and return directory name, build directory and gcov kernel version
+# as found in package.
+#
+
+sub get_package($)
+{
+ my ($file) = @_;
+ my $dir = create_temp_dir();
+ my $gkv;
+ my $build;
+ my $cwd = getcwd();
+ my $count;
+ local *HANDLE;
+
+ info("Reading package $file:\n");
+ info(" data directory .......: $dir\n");
+ $file = abs_path($file);
+ chdir($dir);
+ open(HANDLE, "tar xvfz $file 2>/dev/null|")
+ or die("ERROR: could not process package $file\n");
+ while (<HANDLE>) {
+ if (/\.da$/ || /\.gcda$/) {
+ $count++;
+ }
+ }
+ close(HANDLE);
+ $build = read_file("$dir/$pkg_build_file");
+ if (defined($build)) {
+ info(" build directory ......: $build\n");
+ }
+ $gkv = read_file("$dir/$pkg_gkv_file");
+ if (defined($gkv)) {
+ $gkv = int($gkv);
+ if ($gkv != $GKV_PROC && $gkv != $GKV_SYS) {
+ die("ERROR: unsupported gcov kernel version found ".
+ "($gkv)\n");
+ }
+ info(" content type .........: kernel data\n");
+ info(" gcov kernel version ..: %s\n", $GKV_NAME[$gkv]);
+ } else {
+ info(" content type .........: application data\n");
+ }
+ info(" data files ...........: $count\n");
+ chdir($cwd);
+
+ return ($dir, $build, $gkv);
+}
+
+#
+# write_file(filename, $content)
+#
+# Create a file named filename and write the specified content to it.
+#
+
+sub write_file($$)
+{
+ my ($filename, $content) = @_;
+ local *HANDLE;
+
+ open(HANDLE, ">$filename") || return 0;
+ print(HANDLE $content);
+ close(HANDLE) || return 0;
+
+ return 1;
+}
+
+# count_package_data(filename)
+#
+# Count the number of coverage data files in the specified package file.
+#
+
+sub count_package_data($)
+{
+ my ($filename) = @_;
+ local *HANDLE;
+ my $count = 0;
+
+ open(HANDLE, "tar tfz $filename|") or return undef;
+ while (<HANDLE>) {
+ if (/\.da$/ || /\.gcda$/) {
+ $count++;
+ }
+ }
+ close(HANDLE);
+ return $count;
}
-
-#
-# kernel_reset()
-#
-# Reset kernel coverage.
-#
-# Die on error.
-#
-
-sub kernel_reset()
+#
+# create_package(package_file, source_directory, build_directory[,
+# kernel_gcov_version])
+#
+# Store unprocessed coverage data files from source_directory to package_file.
+#
+
+sub create_package($$$;$)
+{
+ my ($file, $dir, $build, $gkv) = @_;
+ my $cwd = getcwd();
+
+ # Print information about the package
+ info("Creating package $file:\n");
+ info(" data directory .......: $dir\n");
+
+ # Handle build directory
+ if (defined($build)) {
+ info(" build directory ......: $build\n");
+ write_file("$dir/$pkg_build_file", $build)
+ or die("ERROR: could not write to ".
+ "$dir/$pkg_build_file\n");
+ }
+
+ # Handle gcov kernel version data
+ if (defined($gkv)) {
+ info(" content type .........: kernel data\n");
+ info(" gcov kernel version ..: %s\n", $GKV_NAME[$gkv]);
+ write_file("$dir/$pkg_gkv_file", $gkv)
+ or die("ERROR: could not write to ".
+ "$dir/$pkg_gkv_file\n");
+ } else {
+ info(" content type .........: application data\n");
+ }
+
+ # Create package
+ $file = abs_path($file);
+ chdir($dir);
+ system("tar cfz $file .")
+ and die("ERROR: could not create package $file\n");
+
+ # Remove temporary files
+ unlink("$dir/$pkg_build_file");
+ unlink("$dir/$pkg_gkv_file");
+
+ # Show number of data files
+ if (!$quiet) {
+ my $count = count_package_data($file);
+
+ if (defined($count)) {
+ info(" data files ...........: $count\n");
+ }
+ }
+ chdir($cwd);
+}
+
+sub find_link_fn($$$)
+{
+ my ($from, $rel, $filename) = @_;
+ my $absfile = catfile($from, $rel, $filename);
+
+ if (-l $absfile) {
+ return $absfile;
+ }
+ return undef;
+}
+
+#
+# get_base(dir)
+#
+# Return (BASE, OBJ), where
+# - BASE: is the path to the kernel base directory relative to dir
+# - OBJ: is the absolute path to the kernel build directory
+#
+
+sub get_base($)
+{
+ my ($dir) = @_;
+ my $marker = "kernel/gcov/base.gcno";
+ my $markerfile;
+ my $sys;
+ my $obj;
+ my $link;
+
+ $markerfile = lcov_find($dir, \&find_link_fn, $marker);
+ if (!defined($markerfile)) {
+ return (undef, undef);
+ }
+
+ # sys base is parent of parent of markerfile.
+ $sys = abs2rel(dirname(dirname(dirname($markerfile))), $dir);
+
+ # obj base is parent of parent of markerfile link target.
+ $link = readlink($markerfile);
+ if (!defined($link)) {
+ die("ERROR: could not read $markerfile\n");
+ }
+ $obj = dirname(dirname(dirname($link)));
+
+ return ($sys, $obj);
+}
+
+#
+# apply_base_dir(data_dir, base_dir, build_dir, @directories)
+#
+# Make entries in @directories relative to data_dir.
+#
+
+sub apply_base_dir($$$@)
{
- local *HANDLE;
- check_and_load_kernel_module();
-
- info("Resetting kernel execution counters\n");
- open(HANDLE, ">$gcov_dir/vmlinux") or
- die("ERROR: cannot write to $gcov_dir/vmlinux!\n");
- print(HANDLE "0");
- close(HANDLE);
-
- # Unload module if we loaded it in the first place
- if ($need_unload)
- {
- unload_module($need_unload);
+ my ($data, $base, $build, @dirs) = @_;
+ my $dir;
+ my @result;
+
+ foreach $dir (@dirs) {
+ # Is directory path relative to data directory?
+ if (-d catdir($data, $dir)) {
+ push(@result, $dir);
+ next;
+ }
+ # Relative to the auto-detected base-directory?
+ if (defined($base)) {
+ if (-d catdir($data, $base, $dir)) {
+ push(@result, catdir($base, $dir));
+ next;
+ }
+ }
+ # Relative to the specified base-directory?
+ if (defined($base_directory)) {
+ if (file_name_is_absolute($base_directory)) {
+ $base = abs2rel($base_directory, rootdir());
+ } else {
+ $base = $base_directory;
+ }
+ if (-d catdir($data, $base, $dir)) {
+ push(@result, catdir($base, $dir));
+ next;
+ }
+ }
+ # Relative to the build directory?
+ if (defined($build)) {
+ if (file_name_is_absolute($build)) {
+ $base = abs2rel($build, rootdir());
+ } else {
+ $base = $build;
+ }
+ if (-d catdir($data, $base, $dir)) {
+ push(@result, catdir($base, $dir));
+ next;
+ }
+ }
+ die("ERROR: subdirectory $dir not found\n".
+ "Please use -b to specify the correct directory\n");
+ }
+ return @result;
+}
+
+#
+# copy_gcov_dir(dir, [@subdirectories])
+#
+# Create a temporary directory and copy all or, if specified, only some
+# subdirectories from dir to that directory. Return the name of the temporary
+# directory.
+#
+
+sub copy_gcov_dir($;@)
+{
+ my ($data, @dirs) = @_;
+ my $tempdir = create_temp_dir();
+
+ info("Copying data to temporary directory $tempdir\n");
+ lcov_copy($data, $tempdir, @dirs);
+
+ return $tempdir;
+}
+
+#
+# kernel_capture_initial
+#
+# Capture initial kernel coverage data, i.e. create a coverage data file from
+# static graph files which contains zero coverage data for all instrumented
+# lines.
+#
+
+sub kernel_capture_initial()
+{
+ my $build;
+ my $source;
+ my @params;
+
+ if (defined($base_directory)) {
+ $build = $base_directory;
+ $source = "specified";
+ } else {
+ (undef, $build) = get_base($gcov_dir);
+ if (!defined($build)) {
+ die("ERROR: could not auto-detect build directory.\n".
+ "Please use -b to specify the build directory\n");
+ }
+ $source = "auto-detected";
+ }
+ info("Using $build as kernel build directory ($source)\n");
+ # Build directory needs to be passed to geninfo
+ $base_directory = $build;
+ if (@kernel_directory) {
+ foreach my $dir (@kernel_directory) {
+ push(@params, "$build/$dir");
+ }
+ } else {
+ push(@params, $build);
+ }
+ lcov_geninfo(@params);
+}
+
+#
+# kernel_capture_from_dir(directory, gcov_kernel_version, build)
+#
+# Perform the actual kernel coverage capturing from the specified directory
+# assuming that the data was copied from the specified gcov kernel version.
+#
+
+sub kernel_capture_from_dir($$$)
+{
+ my ($dir, $gkv, $build) = @_;
+
+ # Create package or coverage file
+ if (defined($to_package)) {
+ create_package($to_package, $dir, $build, $gkv);
+ } else {
+ # Build directory needs to be passed to geninfo
+ $base_directory = $build;
+ lcov_geninfo($dir);
}
}
-
-#
-# kernel_capture()
-#
-# Capture kernel coverage data and write it to OUTPUT_FILENAME if specified,
-# otherwise stdout.
-#
+#
+# adjust_kernel_dir(dir, build)
+#
+# Adjust directories specified with -k so that they point to the directory
+# relative to DIR. Return the build directory if specified or the auto-
+# detected build-directory.
+#
+
+sub adjust_kernel_dir($$)
+{
+ my ($dir, $build) = @_;
+ my ($sys_base, $build_auto) = get_base($dir);
+
+ if (!defined($build)) {
+ $build = $build_auto;
+ }
+ if (!defined($build)) {
+ die("ERROR: could not auto-detect build directory.\n".
+ "Please use -b to specify the build directory\n");
+ }
+ # Make @kernel_directory relative to sysfs base
+ if (@kernel_directory) {
+ @kernel_directory = apply_base_dir($dir, $sys_base, $build,
+ @kernel_directory);
+ }
+ return $build;
+}
sub kernel_capture()
{
- my @param;
-
- check_and_load_kernel_module();
-
- # Make sure the temporary directory is removed upon script termination
- END
- {
- if ($temp_dir_name)
- {
- stat($temp_dir_name);
- if (-r _)
- {
- info("Removing temporary directory ".
- "$temp_dir_name\n");
-
- # Remove temporary directory
- system("rm", "-rf", $temp_dir_name)
- and warn("WARNING: cannot remove ".
- "temporary directory ".
- "$temp_dir_name!\n");
- }
- }
- }
-
- # Get temporary directory
- $temp_dir_name = create_temp_dir();
-
- info("Copying kernel data to temporary directory $temp_dir_name\n");
-
- if (!@kernel_directory)
- {
- # Copy files from gcov kernel directory
- system("cp", "-dr", $gcov_dir, $temp_dir_name)
- and die("ERROR: cannot copy files from $gcov_dir!\n");
+ my $data_dir;
+ my $build = $base_directory;
+
+ if ($gcov_gkv == $GKV_SYS) {
+ $build = adjust_kernel_dir($gcov_dir, $build);
}
- else
- {
- # Prefix list of kernel sub-directories with the gcov kernel
- # directory
- my $file_list = join(" ", map {"$gcov_dir/$_";}
- @kernel_directory);
-
- # Copy files from gcov kernel directory
- system("cp", "-dr", $file_list, $temp_dir_name)
- and die("ERROR: cannot copy files from $file_list!\n");
+ $data_dir = copy_gcov_dir($gcov_dir, @kernel_directory);
+ kernel_capture_from_dir($data_dir, $gcov_gkv, $build);
+}
+
+#
+# package_capture()
+#
+# Capture coverage data from a package of unprocessed coverage data files
+# as generated by lcov --to-package.
+#
+
+sub package_capture()
+{
+ my $dir;
+ my $build;
+ my $gkv;
+
+ ($dir, $build, $gkv) = get_package($from_package);
+
+ # Check for build directory
+ if (defined($base_directory)) {
+ if (defined($build)) {
+ info("Using build directory specified by -b.\n");
+ }
+ $build = $base_directory;
}
- # Make directories writable
- system("find", $temp_dir_name, "-type", "d", "-exec", "chmod", "u+w",
- "{}", ";")
- and die("ERROR: cannot modify access rights for ".
- "$temp_dir_name!\n");
-
- # Make files writable
- system("find", $temp_dir_name, "-type", "f", "-exec", "chmod", "u+w",
- "{}", ";")
- and die("ERROR: cannot modify access rights for ".
- "$temp_dir_name!\n");
-
- # Capture data
- info("Capturing coverage data from $temp_dir_name\n");
- @param = ("$tool_dir/geninfo", $temp_dir_name);
- if ($output_filename)
- {
- @param = (@param, "--output-filename", $output_filename);
- }
- if ($test_name)
- {
- @param = (@param, "--test-name", $test_name);
- }
- if ($follow)
- {
- @param = (@param, "--follow");
- }
- if ($quiet)
- {
- @param = (@param, "--quiet");
- }
- if ($nochecksum)
- {
- @param = (@param, "--no-checksum");
- }
- system(@param) and exit($? >> 8);
-
-
- # Unload module if we loaded it in the first place
- if ($need_unload)
- {
- unload_module($need_unload);
+ # Do the actual capture
+ if (defined($gkv)) {
+ if ($gkv == $GKV_SYS) {
+ $build = adjust_kernel_dir($dir, $build);
+ }
+ if (@kernel_directory) {
+ $dir = copy_gcov_dir($dir, @kernel_directory);
+ }
+ kernel_capture_from_dir($dir, $gkv, $build);
+ } else {
+ # Build directory needs to be passed to geninfo
+ $base_directory = $build;
+ lcov_geninfo($dir);
}
}
@@ -608,11 +1261,11 @@
# Print info string
if ($to_file)
{
- print(@_)
+ printf(@_)
}
else
{
- # Don't interfer with the .info output to STDOUT
+ # Don't interfere with the .info output to STDOUT
printf(STDERR @_);
}
}
@@ -620,106 +1273,6 @@
#
-# Check if the gcov kernel module is loaded. If it is, exit, if not, try
-# to load it.
-#
-# Die on error.
-#
-
-sub check_and_load_kernel_module()
-{
- my $module_name;
-
- # Is it loaded already?
- stat("$gcov_dir");
- if (-r _) { return(); }
-
- info("Loading required gcov kernel module.\n");
-
- # Do we have access to the insmod tool?
- stat($insmod_tool);
- if (!-x _)
- {
- die("ERROR: need insmod tool ($insmod_tool) to access kernel ".
- "coverage data!\n");
- }
- # Do we have access to the modprobe tool?
- stat($modprobe_tool);
- if (!-x _)
- {
- die("ERROR: need modprobe tool ($modprobe_tool) to access ".
- "kernel coverage data!\n");
- }
-
- # Try some possibilities of where the gcov kernel module may be found
- foreach $module_name (@gcovmod)
- {
- # Try to load module from system wide module directory
- # /lib/modules
- if (system_no_output(3, $modprobe_tool, $module_name) == 0)
- {
- # Succeeded
- $need_unload = $module_name;
- return();
- }
-
- # Try to load linux 2.5/2.6 module from tool directory
- if (system_no_output(3, $insmod_tool,
- "$tool_dir/$module_name.ko") == 0)
- {
- # Succeeded
- $need_unload = $module_name;
- return();
- }
-
- # Try to load linux 2.4 module from tool directory
- if (system_no_output(3, $insmod_tool,
- "$tool_dir/$module_name.o") == 0)
- {
- # Succeeded
- $need_unload = $module_name;
- return();
- }
- }
-
- # Hm, loading failed - maybe we aren't root?
- if ($> != 0)
- {
- die("ERROR: need root access to load kernel module!\n");
- }
-
- die("ERROR: cannot load required gcov kernel module!\n");
-}
-
-
-#
-# unload_module()
-#
-# Unload the gcov kernel module.
-#
-
-sub unload_module($)
-{
- my $module = $_[0];
-
- info("Unloading kernel module $module\n");
-
- # Do we have access to the rmmod tool?
- stat($rmmod_tool);
- if (!-x _)
- {
- warn("WARNING: cannot execute rmmod tool at $rmmod_tool - ".
- "gcov module still loaded!\n");
- }
-
- # Unload gcov kernel module
- system_no_output(1, $rmmod_tool, $module)
- and warn("WARNING: cannot unload gcov kernel module ".
- "$module!\n");
-}
-
-
-#
# create_temp_dir()
#
# Create a temporary directory and return its path.
@@ -729,24 +1282,200 @@
sub create_temp_dir()
{
- my $dirname;
- my $number = sprintf("%d", rand(1000));
-
- # Endless loops are evil
- while ($number++ < 1000)
- {
- $dirname = "$tmp_dir/$tmp_prefix$number";
- stat($dirname);
- if (-e _) { next; }
-
- mkdir($dirname)
- or die("ERROR: cannot create temporary directory ".
- "$dirname!\n");
-
- return($dirname);
+ my $dir;
+
+ if (defined($tmp_dir)) {
+ $dir = tempdir(DIR => $tmp_dir, CLEANUP => 1);
+ } else {
+ $dir = tempdir(CLEANUP => 1);
+ }
+ if (!defined($dir)) {
+ die("ERROR: cannot create temporary directory\n");
}
-
- die("ERROR: cannot create temporary directory in $tmp_dir!\n");
+ push(@temp_dirs, $dir);
+
+ return $dir;
+}
+
+
+#
+# br_taken_to_num(taken)
+#
+# Convert a branch taken value .info format to number format.
+#
+
+sub br_taken_to_num($)
+{
+ my ($taken) = @_;
+
+ return 0 if ($taken eq '-');
+ return $taken + 1;
+}
+
+
+#
+# br_num_to_taken(taken)
+#
+# Convert a branch taken value in number format to .info format.
+#
+
+sub br_num_to_taken($)
+{
+ my ($taken) = @_;
+
+ return '-' if ($taken == 0);
+ return $taken - 1;
+}
+
+
+#
+# br_taken_add(taken1, taken2)
+#
+# Return the result of taken1 + taken2 for 'branch taken' values.
+#
+
+sub br_taken_add($$)
+{
+ my ($t1, $t2) = @_;
+
+ return $t1 if (!defined($t2));
+ return $t2 if (!defined($t1));
+ return $t1 if ($t2 eq '-');
+ return $t2 if ($t1 eq '-');
+ return $t1 + $t2;
+}
+
+
+#
+# br_taken_sub(taken1, taken2)
+#
+# Return the result of taken1 - taken2 for 'branch taken' values. Return 0
+# if the result would become negative.
+#
+
+sub br_taken_sub($$)
+{
+ my ($t1, $t2) = @_;
+
+ return $t1 if (!defined($t2));
+ return undef if (!defined($t1));
+ return $t1 if ($t1 eq '-');
+ return $t1 if ($t2 eq '-');
+ return 0 if $t2 > $t1;
+ return $t1 - $t2;
+}
+
+
+#
+#
+# br_ivec_len(vector)
+#
+# Return the number of entries in the branch coverage vector.
+#
+
+sub br_ivec_len($)
+{
+ my ($vec) = @_;
+
+ return 0 if (!defined($vec));
+ return (length($vec) * 8 / $BR_VEC_WIDTH) / $BR_VEC_ENTRIES;
+}
+
+
+#
+# br_ivec_push(vector, block, branch, taken)
+#
+# Add an entry to the branch coverage vector. If an entry with the same
+# branch ID already exists, add the corresponding taken values.
+#
+
+sub br_ivec_push($$$$)
+{
+ my ($vec, $block, $branch, $taken) = @_;
+ my $offset;
+ my $num = br_ivec_len($vec);
+ my $i;
+
+ $vec = "" if (!defined($vec));
+
+ # Check if branch already exists in vector
+ for ($i = 0; $i < $num; $i++) {
+ my ($v_block, $v_branch, $v_taken) = br_ivec_get($vec, $i);
+
+ next if ($v_block != $block || $v_branch != $branch);
+
+ # Add taken counts
+ $taken = br_taken_add($taken, $v_taken);
+ last;
+ }
+
+ $offset = $i * $BR_VEC_ENTRIES;
+ $taken = br_taken_to_num($taken);
+
+ # Add to vector
+ vec($vec, $offset + $BR_BLOCK, $BR_VEC_WIDTH) = $block;
+ vec($vec, $offset + $BR_BRANCH, $BR_VEC_WIDTH) = $branch;
+ vec($vec, $offset + $BR_TAKEN, $BR_VEC_WIDTH) = $taken;
+
+ return $vec;
+}
+
+
+#
+# br_ivec_get(vector, number)
+#
+# Return an entry from the branch coverage vector.
+#
+
+sub br_ivec_get($$)
+{
+ my ($vec, $num) = @_;
+ my $block;
+ my $branch;
+ my $taken;
+ my $offset = $num * $BR_VEC_ENTRIES;
+
+ # Retrieve data from vector
+ $block = vec($vec, $offset + $BR_BLOCK, $BR_VEC_WIDTH);
+ $branch = vec($vec, $offset + $BR_BRANCH, $BR_VEC_WIDTH);
+ $taken = vec($vec, $offset + $BR_TAKEN, $BR_VEC_WIDTH);
+
+ # Decode taken value from an integer
+ $taken = br_num_to_taken($taken);
+
+ return ($block, $branch, $taken);
+}
+
+
+#
+# get_br_found_and_hit(brcount)
+#
+# Return (br_found, br_hit) for brcount
+#
+
+sub get_br_found_and_hit($)
+{
+ my ($brcount) = @_;
+ my $line;
+ my $br_found = 0;
+ my $br_hit = 0;
+
+ foreach $line (keys(%{$brcount})) {
+ my $brdata = $brcount->{$line};
+ my $i;
+ my $num = br_ivec_len($brdata);
+
+ for ($i = 0; $i < $num; $i++) {
+ my $taken;
+
+ (undef, undef, $taken) = br_ivec_get($brdata, $i);
+
+ $br_found++;
+ $br_hit++ if ($taken ne "-" && $taken > 0);
+ }
+ }
+
+ return ($br_found, $br_hit);
}
@@ -764,13 +1493,24 @@
# "found" -> $lines_found (number of instrumented lines found in file)
# "hit" -> $lines_hit (number of executed lines in file)
# "check" -> \%checkdata
-#
-# %testdata: name of test affecting this file -> \%testcount
-#
-# %testcount: line number -> execution count for a single test
-# %sumcount : line number -> execution count for all tests
-# %funcdata : line number -> name of function beginning at that line
-# %checkdata: line number -> checksum of source code line
+# "testfnc" -> \%testfncdata
+# "sumfnc" -> \%sumfnccount
+# "testbr" -> \%testbrdata
+# "sumbr" -> \%sumbrcount
+#
+# %testdata : name of test affecting this file -> \%testcount
+# %testfncdata: name of test affecting this file -> \%testfnccount
+# %testbrdata: name of test affecting this file -> \%testbrcount
+#
+# %testcount : line number -> execution count for a single test
+# %testfnccount: function name -> execution count for a single test
+# %testbrcount : line number -> branch coverage data for a single test
+# %sumcount : line number -> execution count for all tests
+# %sumfnccount : function name -> execution count for all tests
+# %sumbrcount : line number -> branch coverage data for all tests
+# %funcdata : function name -> line number
+# %checkdata : line number -> checksum of source code line
+# $brdata : vector of items: block, branch, taken
#
# Note that .info file sections referring to the same file and test name
# will automatically be combined by adding all execution counts.
@@ -792,13 +1532,20 @@
my $sumcount; # " "
my $funcdata; # " "
my $checkdata; # " "
+ my $testfncdata;
+ my $testfnccount;
+ my $sumfnccount;
+ my $testbrdata;
+ my $testbrcount;
+ my $sumbrcount;
my $line; # Current line read from .info file
my $testname; # Current test name
my $filename; # Current filename
my $hitcount; # Count for lines hit
my $count; # Execution count of current line
my $negative; # If set, warn about negative counts
- my $checksum; # Checksum of current line
+ my $changed_testname; # If set, warn about changed testname
+ my $line_checksum; # Checksum of current line
local *INFO_HANDLE; # Filehandle for .info file
info("Reading tracefile $tracefile\n");
@@ -849,10 +1596,15 @@
# Switch statement
foreach ($line)
{
- /^TN:(\w*(,\w+)?)/ && do
+ /^TN:([^,]*)(,diff)?/ && do
{
# Test name information found
$testname = defined($1) ? $1 : "";
+ if ($testname =~ s/\W/_/g)
+ {
+ $changed_testname = 1;
+ }
+ $testname .= $2 if (defined($2));
last;
};
@@ -863,17 +1615,22 @@
$filename = $1;
$data = $result{$filename};
- ($testdata, $sumcount, $funcdata, $checkdata) =
+ ($testdata, $sumcount, $funcdata, $checkdata,
+ $testfncdata, $sumfnccount, $testbrdata,
+ $sumbrcount) =
get_info_entry($data);
if (defined($testname))
{
$testcount = $testdata->{$testname};
+ $testfnccount = $testfncdata->{$testname};
+ $testbrcount = $testbrdata->{$testname};
}
else
{
- my %new_hash;
- $testcount = \%new_hash;
+ $testcount = {};
+ $testfnccount = {};
+ $testbrcount = {};
}
last;
};
@@ -899,17 +1656,18 @@
# Store line checksum if available
if (defined($3))
{
- $checksum = substr($3, 1);
+ $line_checksum = substr($3, 1);
# Does it match a previous definition
if (defined($checkdata->{$1}) &&
- ($checkdata->{$1} ne $checksum))
+ ($checkdata->{$1} ne
+ $line_checksum))
{
die("ERROR: checksum mismatch ".
"at $filename:$1\n");
}
- $checkdata->{$1} = $checksum;
+ $checkdata->{$1} = $line_checksum;
}
last;
};
@@ -917,7 +1675,52 @@
/^FN:(\d+),([^,]+)/ && do
{
# Function data found, add to structure
- $funcdata->{$1} = $2;
+ $funcdata->{$2} = $1;
+
+ # Also initialize function call data
+ if (!defined($sumfnccount->{$2})) {
+ $sumfnccount->{$2} = 0;
+ }
+ if (defined($testname))
+ {
+ if (!defined($testfnccount->{$2})) {
+ $testfnccount->{$2} = 0;
+ }
+ }
+ last;
+ };
+
+ /^FNDA:(\d+),([^,]+)/ && do
+ {
+ # Function call count found, add to structure
+ # Add summary counts
+ $sumfnccount->{$2} += $1;
+
+ # Add test-specific counts
+ if (defined($testname))
+ {
+ $testfnccount->{$2} += $1;
+ }
+ last;
+ };
+
+ /^BRDA:(\d+),(\d+),(\d+),(\d+|-)/ && do {
+ # Branch coverage data found
+ my ($line, $block, $branch, $taken) =
+ ($1, $2, $3, $4);
+
+ $sumbrcount->{$line} =
+ br_ivec_push($sumbrcount->{$line},
+ $block, $branch, $taken);
+
+ # Add test-specific counts
+ if (defined($testname)) {
+ $testbrcount->{$line} =
+ br_ivec_push(
+ $testbrcount->{$line},
+ $block, $branch,
+ $taken);
+ }
last;
};
@@ -931,10 +1734,18 @@
{
$testdata->{$testname} =
$testcount;
+ $testfncdata->{$testname} =
+ $testfnccount;
+ $testbrdata->{$testname} =
+ $testbrcount;
}
+
set_info_entry($data, $testdata,
$sumcount, $funcdata,
- $checkdata);
+ $checkdata, $testfncdata,
+ $sumfnccount,
+ $testbrdata,
+ $sumbrcount);
$result{$filename} = $data;
last;
}
@@ -946,25 +1757,29 @@
}
close(INFO_HANDLE);
- # Calculate lines_found and lines_hit for each file
+ # Calculate hit and found values for lines and functions of each file
foreach $filename (keys(%result))
{
$data = $result{$filename};
- ($testdata, $sumcount, $funcdata) = get_info_entry($data);
-
- # Filter out empty test cases
+ ($testdata, $sumcount, undef, undef, $testfncdata,
+ $sumfnccount, $testbrdata, $sumbrcount) =
+ get_info_entry($data);
+
+ # Filter out empty files
if (scalar(keys(%{$sumcount})) == 0)
{
delete($result{$filename});
next;
}
+ # Filter out empty test cases
foreach $testname (keys(%{$testdata}))
{
if (!defined($testdata->{$testname}) ||
scalar(keys(%{$testdata->{$testname}})) == 0)
{
delete($testdata->{$testname});
+ delete($testfncdata->{$testname});
}
}
@@ -978,7 +1793,24 @@
$data->{"hit"} = $hitcount;
- $result{$filename} = $data;
+ # Get found/hit values for function call data
+ $data->{"f_found"} = scalar(keys(%{$sumfnccount}));
+ $hitcount = 0;
+
+ foreach (keys(%{$sumfnccount})) {
+ if ($sumfnccount->{$_} > 0) {
+ $hitcount++;
+ }
+ }
+ $data->{"f_hit"} = $hitcount;
+
+ # Get found/hit values for branch data
+ {
+ my ($br_found, $br_hit) = get_br_found_and_hit($sumbrcount);
+
+ $data->{"b_found"} = $br_found;
+ $data->{"b_hit"} = $br_hit;
+ }
}
if (scalar(keys(%result)) == 0)
@@ -990,6 +1822,11 @@
warn("WARNING: negative counts found in tracefile ".
"$tracefile\n");
}
+ if ($changed_testname)
+ {
+ warn("WARNING: invalid characters removed from testname in ".
+ "tracefile $tracefile\n");
+ }
return(\%result);
}
@@ -1001,7 +1838,9 @@
# Retrieve data from an entry of the structure generated by read_info_file().
# Return a list of references to hashes:
# (test data hash ref, sum count hash ref, funcdata hash ref, checkdata hash
-# ref, lines found, lines hit)
+# ref, testfncdata hash ref, sumfnccount hash ref, testbrdata hash ref,
+# sumbrcount hash ref, lines found, lines hit, functions found,
+# functions hit, branches found, branches hit)
#
sub get_info_entry($)
@@ -1010,22 +1849,34 @@
my $sumcount_ref = $_[0]->{"sum"};
my $funcdata_ref = $_[0]->{"func"};
my $checkdata_ref = $_[0]->{"check"};
+ my $testfncdata = $_[0]->{"testfnc"};
+ my $sumfnccount = $_[0]->{"sumfnc"};
+ my $testbrdata = $_[0]->{"testbr"};
+ my $sumbrcount = $_[0]->{"sumbr"};
my $lines_found = $_[0]->{"found"};
my $lines_hit = $_[0]->{"hit"};
+ my $f_found = $_[0]->{"f_found"};
+ my $f_hit = $_[0]->{"f_hit"};
+ my $br_found = $_[0]->{"b_found"};
+ my $br_hit = $_[0]->{"b_hit"};
return ($testdata_ref, $sumcount_ref, $funcdata_ref, $checkdata_ref,
- $lines_found, $lines_hit);
+ $testfncdata, $sumfnccount, $testbrdata, $sumbrcount,
+ $lines_found, $lines_hit, $f_found, $f_hit,
+ $br_found, $br_hit);
}
#
# set_info_entry(hash_ref, testdata_ref, sumcount_ref, funcdata_ref,
-# checkdata_ref[,lines_found, lines_hit])
+# checkdata_ref, testfncdata_ref, sumfcncount_ref,
+# testbrdata_ref, sumbrcount_ref[,lines_found,
+# lines_hit, f_found, f_hit, $b_found, $b_hit])
#
# Update the hash referenced by HASH_REF with the provided data references.
#
-sub set_info_entry($$$$$;$$)
+sub set_info_entry($$$$$$$$$;$$$$$$)
{
my $data_ref = $_[0];
@@ -1033,9 +1884,17 @@
$data_ref->{"sum"} = $_[2];
$data_ref->{"func"} = $_[3];
$data_ref->{"check"} = $_[4];
-
- if (defined($_[5])) { $data_ref->{"found"} = $_[5]; }
- if (defined($_[6])) { $data_ref->{"hit"} = $_[6]; }
+ $data_ref->{"testfnc"} = $_[5];
+ $data_ref->{"sumfnc"} = $_[6];
+ $data_ref->{"testbr"} = $_[7];
+ $data_ref->{"sumbr"} = $_[8];
+
+ if (defined($_[9])) { $data_ref->{"found"} = $_[9]; }
+ if (defined($_[10])) { $data_ref->{"hit"} = $_[10]; }
+ if (defined($_[11])) { $data_ref->{"f_found"} = $_[11]; }
+ if (defined($_[12])) { $data_ref->{"f_hit"} = $_[12]; }
+ if (defined($_[13])) { $data_ref->{"b_found"} = $_[13]; }
+ if (defined($_[14])) { $data_ref->{"b_hit"} = $_[14]; }
}
@@ -1134,48 +1993,262 @@
#
-# merge_func_data(ref1, ref2, filename)
+# merge_func_data(funcdata1, funcdata2, filename)
#
sub merge_func_data($$$)
{
- my $ref1 = $_[0];
- my $ref2 = $_[1];
- my $filename = $_[2];
+ my ($funcdata1, $funcdata2, $filename) = @_;
+ my %result;
+ my $func;
+
+ if (defined($funcdata1)) {
+ %result = %{$funcdata1};
+ }
+
+ foreach $func (keys(%{$funcdata2})) {
+ my $line1 = $result{$func};
+ my $line2 = $funcdata2->{$func};
+
+ if (defined($line1) && ($line1 != $line2)) {
+ warn("WARNING: function data mismatch at ".
+ "$filename:$line2\n");
+ next;
+ }
+ $result{$func} = $line2;
+ }
+
+ return \%result;
+}
+
+
+#
+# add_fnccount(fnccount1, fnccount2)
+#
+# Add function call count data. Return list (fnccount_added, f_found, f_hit)
+#
+
+sub add_fnccount($$)
+{
+ my ($fnccount1, $fnccount2) = @_;
+ my %result;
+ my $f_found;
+ my $f_hit;
+ my $function;
+
+ if (defined($fnccount1)) {
+ %result = %{$fnccount1};
+ }
+ foreach $function (keys(%{$fnccount2})) {
+ $result{$function} += $fnccount2->{$function};
+ }
+ $f_found = scalar(keys(%result));
+ $f_hit = 0;
+ foreach $function (keys(%result)) {
+ if ($result{$function} > 0) {
+ $f_hit++;
+ }
+ }
+
+ return (\%result, $f_found, $f_hit);
+}
+
+#
+# add_testfncdata(testfncdata1, testfncdata2)
+#
+# Add function call count data for several tests. Return reference to
+# added_testfncdata.
+#
+
+sub add_testfncdata($$)
+{
+ my ($testfncdata1, $testfncdata2) = @_;
my %result;
- my %ignore;
- my $line1;
- my $line2;
-
- # Check for mismatch
- foreach $line1 (keys(%{$ref1}))
- {
- foreach $line2 (keys(%{$ref2}))
- {
- if (($ref1->{$line1} eq $ref2->{$line2}) &&
- ($line1 != $line2))
- {
- warn("WARNING: function data mismatch at ".
- "$filename:$ref1->{$line1}\n");
- $ignore{$line2} = 1;
+ my $testname;
+
+ foreach $testname (keys(%{$testfncdata1})) {
+ if (defined($testfncdata2->{$testname})) {
+ my $fnccount;
+
+ # Function call count data for this testname exists
+ # in both data sets: merge
+ ($fnccount) = add_fnccount(
+ $testfncdata1->{$testname},
+ $testfncdata2->{$testname});
+ $result{$testname} = $fnccount;
+ next;
+ }
+ # Function call count data for this testname is unique to
+ # data set 1: copy
+ $result{$testname} = $testfncdata1->{$testname};
+ }
+
+ # Add count data for testnames unique to data set 2
+ foreach $testname (keys(%{$testfncdata2})) {
+ if (!defined($result{$testname})) {
+ $result{$testname} = $testfncdata2->{$testname};
+ }
+ }
+ return \%result;
+}
+
+
+#
+# brcount_to_db(brcount)
+#
+# Convert brcount data to the following format:
+#
+# db: line number -> block hash
+# block hash: block number -> branch hash
+# branch hash: branch number -> taken value
+#
+
+sub brcount_to_db($)
+{
+ my ($brcount) = @_;
+ my $line;
+ my $db;
+
+ # Add branches from first count to database
+ foreach $line (keys(%{$brcount})) {
+ my $brdata = $brcount->{$line};
+ my $i;
+ my $num = br_ivec_len($brdata);
+
+ for ($i = 0; $i < $num; $i++) {
+ my ($block, $branch, $taken) = br_ivec_get($brdata, $i);
+
+ $db->{$line}->{$block}->{$branch} = $taken;
+ }
+ }
+
+ return $db;
+}
+
+
+#
+# db_to_brcount(db)
+#
+# Convert branch coverage data back to brcount format.
+#
+
+sub db_to_brcount($)
+{
+ my ($db) = @_;
+ my $line;
+ my $brcount = {};
+ my $br_found = 0;
+ my $br_hit = 0;
+
+ # Convert database back to brcount format
+ foreach $line (sort({$a <=> $b} keys(%{$db}))) {
+ my $ldata = $db->{$line};
+ my $brdata;
+ my $block;
+
+ foreach $block (sort({$a <=> $b} keys(%{$ldata}))) {
+ my $bdata = $ldata->{$block};
+ my $branch;
+
+ foreach $branch (sort({$a <=> $b} keys(%{$bdata}))) {
+ my $taken = $bdata->{$branch};
+
+ $br_found++;
+ $br_hit++ if ($taken ne "-" && $taken > 0);
+ $brdata = br_ivec_push($brdata, $block,
+ $branch, $taken);
}
}
- }
-
- # Merge
- foreach (keys(%{$ref1}))
- {
- $result{$_} = $ref1->{$_};
+ $brcount->{$line} = $brdata;
}
- foreach (keys(%{$ref2}))
- {
- if (!$ignore{$_})
- {
- $result{$_} = $ref2->{$_};
+ return ($brcount, $br_found, $br_hit);
+}
+
+
+# combine_brcount(brcount1, brcount2, type)
+#
+# If add is BR_ADD, add branch coverage data and return list (brcount_added,
+# br_found, br_hit). If add is BR_SUB, subtract the taken values of brcount2
+# from brcount1 and return (brcount_sub, br_found, br_hit).
+#
+
+sub combine_brcount($$$)
+{
+ my ($brcount1, $brcount2, $type) = @_;
+ my $line;
+ my $block;
+ my $branch;
+ my $taken;
+ my $db;
+ my $br_found = 0;
+ my $br_hit = 0;
+ my $result;
+
+ # Convert branches from first count to database
+ $db = brcount_to_db($brcount1);
+ # Combine values from database and second count
+ foreach $line (keys(%{$brcount2})) {
+ my $brdata = $brcount2->{$line};
+ my $num = br_ivec_len($brdata);
+ my $i;
+
+ for ($i = 0; $i < $num; $i++) {
+ ($block, $branch, $taken) = br_ivec_get($brdata, $i);
+ my $new_taken = $db->{$line}->{$block}->{$branch};
+
+ if ($type == $BR_ADD) {
+ $new_taken = br_taken_add($new_taken, $taken);
+ } elsif ($type == $BR_SUB) {
+ $new_taken = br_taken_sub($new_taken, $taken);
+ }
+ $db->{$line}->{$block}->{$branch} = $new_taken
+ if (defined($new_taken));
}
}
-
+ # Convert database back to brcount format
+ ($result, $br_found, $br_hit) = db_to_brcount($db);
+
+ return ($result, $br_found, $br_hit);
+}
+
+
+#
+# add_testbrdata(testbrdata1, testbrdata2)
+#
+# Add branch coverage data for several tests. Return reference to
+# added_testbrdata.
+#
+
+sub add_testbrdata($$)
+{
+ my ($testbrdata1, $testbrdata2) = @_;
+ my %result;
+ my $testname;
+
+ foreach $testname (keys(%{$testbrdata1})) {
+ if (defined($testbrdata2->{$testname})) {
+ my $brcount;
+
+ # Branch coverage data for this testname exists
+ # in both data sets: add
+ ($brcount) = combine_brcount(
+ $testbrdata1->{$testname},
+ $testbrdata2->{$testname}, $BR_ADD);
+ $result{$testname} = $brcount;
+ next;
+ }
+ # Branch coverage data for this testname is unique to
+ # data set 1: copy
+ $result{$testname} = $testbrdata1->{$testname};
+ }
+
+ # Add count data for testnames unique to data set 2
+ foreach $testname (keys(%{$testbrdata2})) {
+ if (!defined($result{$testname})) {
+ $result{$testname} = $testbrdata2->{$testname};
+ }
+ }
return \%result;
}
@@ -1194,35 +2267,61 @@
my $sumcount1;
my $funcdata1;
my $checkdata1;
+ my $testfncdata1;
+ my $sumfnccount1;
+ my $testbrdata1;
+ my $sumbrcount1;
my $entry2 = $_[1]; # Reference to hash containing second entry
my $testdata2;
my $sumcount2;
my $funcdata2;
my $checkdata2;
+ my $testfncdata2;
+ my $sumfnccount2;
+ my $testbrdata2;
+ my $sumbrcount2;
my %result; # Hash containing combined entry
my %result_testdata;
my $result_sumcount = {};
my $result_funcdata;
+ my $result_testfncdata;
+ my $result_sumfnccount;
+ my $result_testbrdata;
+ my $result_sumbrcount;
my $lines_found;
my $lines_hit;
+ my $f_found;
+ my $f_hit;
+ my $br_found;
+ my $br_hit;
my $testname;
my $filename = $_[2];
# Retrieve data
- ($testdata1, $sumcount1, $funcdata1, $checkdata1) =
- get_info_entry($entry1);
- ($testdata2, $sumcount2, $funcdata2, $checkdata2) =
- get_info_entry($entry2);
+ ($testdata1, $sumcount1, $funcdata1, $checkdata1, $testfncdata1,
+ $sumfnccount1, $testbrdata1, $sumbrcount1) = get_info_entry($entry1);
+ ($testdata2, $sumcount2, $funcdata2, $checkdata2, $testfncdata2,
+ $sumfnccount2, $testbrdata2, $sumbrcount2) = get_info_entry($entry2);
# Merge checksums
$checkdata1 = merge_checksums($checkdata1, $checkdata2, $filename);
# Combine funcdata
$result_funcdata = merge_func_data($funcdata1, $funcdata2, $filename);
-
+
+ # Combine function call count data
+ $result_testfncdata = add_testfncdata($testfncdata1, $testfncdata2);
+ ($result_sumfnccount, $f_found, $f_hit) =
+ add_fnccount($sumfnccount1, $sumfnccount2);
+
+ # Combine branch coverage data
+ $result_testbrdata = add_testbrdata($testbrdata1, $testbrdata2);
+ ($result_sumbrcount, $br_found, $br_hit) =
+ combine_brcount($sumbrcount1, $sumbrcount2, $BR_ADD);
+
# Combine testdata
foreach $testname (keys(%{$testdata1}))
{
@@ -1264,8 +2363,10 @@
# Store result
set_info_entry(\%result, \%result_testdata, $result_sumcount,
- $result_funcdata, $checkdata1, $lines_found,
- $lines_hit);
+ $result_funcdata, $checkdata1, $result_testfncdata,
+ $result_sumfnccount, $result_testbrdata,
+ $result_sumbrcount, $lines_found, $lines_hit,
+ $f_found, $f_hit, $br_found, $br_hit);
return(\%result);
}
@@ -1315,6 +2416,7 @@
my $total_trace;
my $current_trace;
my $tracefile;
+ my @result;
local *INFO_HANDLE;
info("Combining tracefiles.\n");
@@ -1339,13 +2441,15 @@
info("Writing data to $output_filename\n");
open(INFO_HANDLE, ">$output_filename")
or die("ERROR: cannot write to $output_filename!\n");
- write_info_file(*INFO_HANDLE, $total_trace);
+ @result = write_info_file(*INFO_HANDLE, $total_trace);
close(*INFO_HANDLE);
}
else
{
- write_info_file(*STDOUT, $total_trace);
+ @result = write_info_file(*STDOUT, $total_trace);
}
+
+ return @result;
}
@@ -1363,38 +2467,106 @@
my $sumcount;
my $funcdata;
my $checkdata;
+ my $testfncdata;
+ my $sumfnccount;
+ my $testbrdata;
+ my $sumbrcount;
my $testname;
my $line;
+ my $func;
my $testcount;
+ my $testfnccount;
+ my $testbrcount;
my $found;
my $hit;
-
- foreach $source_file (keys(%data))
+ my $f_found;
+ my $f_hit;
+ my $br_found;
+ my $br_hit;
+ my $ln_total_found = 0;
+ my $ln_total_hit = 0;
+ my $fn_total_found = 0;
+ my $fn_total_hit = 0;
+ my $br_total_found = 0;
+ my $br_total_hit = 0;
+
+ foreach $source_file (sort(keys(%data)))
{
$entry = $data{$source_file};
- ($testdata, $sumcount, $funcdata, $checkdata) =
+ ($testdata, $sumcount, $funcdata, $checkdata, $testfncdata,
+ $sumfnccount, $testbrdata, $sumbrcount, $found, $hit,
+ $f_found, $f_hit, $br_found, $br_hit) =
get_info_entry($entry);
- foreach $testname (keys(%{$testdata}))
+
+ # Add to totals
+ $ln_total_found += $found;
+ $ln_total_hit += $hit;
+ $fn_total_found += $f_found;
+ $fn_total_hit += $f_hit;
+ $br_total_found += $br_found;
+ $br_total_hit += $br_hit;
+
+ foreach $testname (sort(keys(%{$testdata})))
{
$testcount = $testdata->{$testname};
+ $testfnccount = $testfncdata->{$testname};
+ $testbrcount = $testbrdata->{$testname};
$found = 0;
$hit = 0;
print(INFO_HANDLE "TN:$testname\n");
print(INFO_HANDLE "SF:$source_file\n");
- foreach $line (sort({$a <=> $b} keys(%{$funcdata})))
+ # Write function related data
+ foreach $func (
+ sort({$funcdata->{$a} <=> $funcdata->{$b}}
+ keys(%{$funcdata})))
{
- print(INFO_HANDLE "FN:$line,".
- $funcdata->{$line}."\n");
+ print(INFO_HANDLE "FN:".$funcdata->{$func}.
+ ",$func\n");
+ }
+ foreach $func (keys(%{$testfnccount})) {
+ print(INFO_HANDLE "FNDA:".
+ $testfnccount->{$func}.
+ ",$func\n");
}
-
+ ($f_found, $f_hit) =
+ get_func_found_and_hit($testfnccount);
+ print(INFO_HANDLE "FNF:$f_found\n");
+ print(INFO_HANDLE "FNH:$f_hit\n");
+
+ # Write branch related data
+ $br_found = 0;
+ $br_hit = 0;
+ foreach $line (sort({$a <=> $b}
+ keys(%{$testbrcount}))) {
+ my $brdata = $testbrcount->{$line};
+ my $num = br_ivec_len($brdata);
+ my $i;
+
+ for ($i = 0; $i < $num; $i++) {
+ my ($block, $branch, $taken) =
+ br_ivec_get($brdata, $i);
+
+ print(INFO_HANDLE "BRDA:$line,$block,".
+ "$branch,$taken\n");
+ $br_found++;
+ $br_hit++ if ($taken ne '-' &&
+ $taken > 0);
+ }
+ }
+ if ($br_found > 0) {
+ print(INFO_HANDLE "BRF:$br_found\n");
+ print(INFO_HANDLE "BRH:$br_hit\n");
+ }
+
+ # Write line related data
foreach $line (sort({$a <=> $b} keys(%{$testcount})))
{
print(INFO_HANDLE "DA:$line,".
$testcount->{$line}.
(defined($checkdata->{$line}) &&
- !$nochecksum ?
+ $checksum ?
",".$checkdata->{$line} : "")."\n");
$found++;
if ($testcount->{$line} > 0)
@@ -1408,6 +2580,9 @@
print(INFO_HANDLE "end_of_record\n");
}
}
+
+ return ($ln_total_found, $ln_total_hit, $fn_total_found, $fn_total_hit,
+ $br_total_found, $br_total_hit);
}
@@ -1461,6 +2636,7 @@
my $pattern;
my @pattern_list;
my $extracted = 0;
+ my @result;
local *INFO_HANDLE;
# Need perlreg expressions instead of shell pattern
@@ -1495,13 +2671,15 @@
info("Writing data to $output_filename\n");
open(INFO_HANDLE, ">$output_filename")
or die("ERROR: cannot write to $output_filename!\n");
- write_info_file(*INFO_HANDLE, $data);
+ @result = write_info_file(*INFO_HANDLE, $data);
close(*INFO_HANDLE);
}
else
{
- write_info_file(*STDOUT, $data);
+ @result = write_info_file(*STDOUT, $data);
}
+
+ return @result;
}
@@ -1517,6 +2695,7 @@
my $pattern;
my @pattern_list;
my $removed = 0;
+ my @result;
local *INFO_HANDLE;
# Need perlreg expressions instead of shell pattern
@@ -1548,17 +2727,127 @@
info("Writing data to $output_filename\n");
open(INFO_HANDLE, ">$output_filename")
or die("ERROR: cannot write to $output_filename!\n");
- write_info_file(*INFO_HANDLE, $data);
+ @result = write_info_file(*INFO_HANDLE, $data);
close(*INFO_HANDLE);
}
else
{
- write_info_file(*STDOUT, $data);
+ @result = write_info_file(*STDOUT, $data);
+ }
+
+ return @result;
+}
+
+
+# get_prefix(max_width, max_percentage_too_long, path_list)
+#
+# Return a path prefix that satisfies the following requirements:
+# - is shared by more paths in path_list than any other prefix
+# - the percentage of paths which would exceed the given max_width length
+# after applying the prefix does not exceed max_percentage_too_long
+#
+# If multiple prefixes satisfy all requirements, the longest prefix is
+# returned. Return an empty string if no prefix could be found.
+
+sub get_prefix($$@)
+{
+ my ($max_width, $max_long, @path_list) = @_;
+ my $path;
+ my $ENTRY_NUM = 0;
+ my $ENTRY_LONG = 1;
+ my %prefix;
+
+ # Build prefix hash
+ foreach $path (@path_list) {
+ my ($v, $d, $f) = splitpath($path);
+ my @dirs = splitdir($d);
+ my $p_len = length($path);
+ my $i;
+
+ # Remove trailing '/'
+ pop(@dirs) if ($dirs[scalar(@dirs) - 1] eq '');
+ for ($i = 0; $i < scalar(@dirs); $i++) {
+ my $subpath = catpath($v, catdir(@dirs[0..$i]), '');
+ my $entry = $prefix{$subpath};
+
+ $entry = [ 0, 0 ] if (!defined($entry));
+ $entry->[$ENTRY_NUM]++;
+ if (($p_len - length($subpath) - 1) > $max_width) {
+ $entry->[$ENTRY_LONG]++;
+ }
+ $prefix{$subpath} = $entry;
+ }
}
+ # Find suitable prefix (sort descending by two keys: 1. number of
+ # entries covered by a prefix, 2. length of prefix)
+ foreach $path (sort {($prefix{$a}->[$ENTRY_NUM] ==
+ $prefix{$b}->[$ENTRY_NUM]) ?
+ length($b) <=> length($a) :
+ $prefix{$b}->[$ENTRY_NUM] <=>
+ $prefix{$a}->[$ENTRY_NUM]}
+ keys(%prefix)) {
+ my ($num, $long) = @{$prefix{$path}};
+
+ # Check for additional requirement: number of filenames
+ # that would be too long may not exceed a certain percentage
+ if ($long <= $num * $max_long / 100) {
+ return $path;
+ }
+ }
+
+ return "";
}
#
+# shorten_filename(filename, width)
+#
+# Truncate filename if it is longer than width characters.
+#
+
+sub shorten_filename($$)
+{
+ my ($filename, $width) = @_;
+ my $l = length($filename);
+ my $s;
+ my $e;
+
+ return $filename if ($l <= $width);
+ $e = int(($width - 3) / 2);
+ $s = $width - 3 - $e;
+
+ return substr($filename, 0, $s).'...'.substr($filename, $l - $e);
+}
+
+
+sub shorten_number($$)
+{
+ my ($number, $width) = @_;
+ my $result = sprintf("%*d", $width, $number);
+
+ return $result if (length($result) <= $width);
+ $number = $number / 1000;
+ return $result if (length($result) <= $width);
+ $result = sprintf("%*dk", $width - 1, $number);
+ return $result if (length($result) <= $width);
+ $number = $number / 1000;
+ $result = sprintf("%*dM", $width - 1, $number);
+ return $result if (length($result) <= $width);
+ return '#';
+}
+
+sub shorten_rate($$)
+{
+ my ($rate, $width) = @_;
+ my $result = sprintf("%*.1f%%", $width - 3, $rate);
+
+ return $result if (length($result) <= $width);
+ $result = sprintf("%*d%%", $width - 1, $rate);
+ return $result if (length($result) <= $width);
+ return "#";
+}
+
+#
# list()
#
@@ -1569,17 +2858,278 @@
my $found;
my $hit;
my $entry;
-
- info("Listing contents of $list:\n");
-
- # List all files
+ my $fn_found;
+ my $fn_hit;
+ my $br_found;
+ my $br_hit;
+ my $total_found = 0;
+ my $total_hit = 0;
+ my $fn_total_found = 0;
+ my $fn_total_hit = 0;
+ my $br_total_found = 0;
+ my $br_total_hit = 0;
+ my $prefix;
+ my $strlen = length("Filename");
+ my $format;
+ my $heading1;
+ my $heading2;
+ my @footer;
+ my $barlen;
+ my $rate;
+ my $fnrate;
+ my $brrate;
+ my $lastpath;
+ my $F_LN_NUM = 0;
+ my $F_LN_RATE = 1;
+ my $F_FN_NUM = 2;
+ my $F_FN_RATE = 3;
+ my $F_BR_NUM = 4;
+ my $F_BR_RATE = 5;
+ my @fwidth_narrow = (5, 5, 3, 5, 4, 5);
+ my @fwidth_wide = (6, 5, 5, 5, 6, 5);
+ my @fwidth = @fwidth_wide;
+ my $w;
+ my $max_width = $opt_list_width;
+ my $max_long = $opt_list_truncate_max;
+ my $fwidth_narrow_length;
+ my $fwidth_wide_length;
+ my $got_prefix = 0;
+ my $root_prefix = 0;
+
+ # Calculate total width of narrow fields
+ $fwidth_narrow_length = 0;
+ foreach $w (@fwidth_narrow) {
+ $fwidth_narrow_length += $w + 1;
+ }
+ # Calculate total width of wide fields
+ $fwidth_wide_length = 0;
+ foreach $w (@fwidth_wide) {
+ $fwidth_wide_length += $w + 1;
+ }
+ # Get common file path prefix
+ $prefix = get_prefix($max_width - $fwidth_narrow_length, $max_long,
+ keys(%{$data}));
+ $root_prefix = 1 if ($prefix eq rootdir());
+ $got_prefix = 1 if (length($prefix) > 0);
+ $prefix =~ s/\/$//;
+ # Get longest filename length
+ foreach $filename (keys(%{$data})) {
+ if (!$opt_list_full_path) {
+ if (!$got_prefix || !$root_prefix &&
+ !($filename =~ s/^\Q$prefix\/\E//)) {
+ my ($v, $d, $f) = splitpath($filename);
+
+ $filename = $f;
+ }
+ }
+ # Determine maximum length of entries
+ if (length($filename) > $strlen) {
+ $strlen = length($filename)
+ }
+ }
+ if (!$opt_list_full_path) {
+ my $blanks;
+
+ $w = $fwidth_wide_length;
+ # Check if all columns fit into max_width characters
+ if ($strlen + $fwidth_wide_length > $max_width) {
+ # Use narrow fields
+ @fwidth = @fwidth_narrow;
+ $w = $fwidth_narrow_length;
+ if (($strlen + $fwidth_narrow_length) > $max_width) {
+ # Truncate filenames at max width
+ $strlen = $max_width - $fwidth_narrow_length;
+ }
+ }
+ # Add some blanks between filename and fields if possible
+ $blanks = int($strlen * 0.5);
+ $blanks = 4 if ($blanks < 4);
+ $blanks = 8 if ($blanks > 8);
+ if (($strlen + $w + $blanks) < $max_width) {
+ $strlen += $blanks;
+ } else {
+ $strlen = $max_width - $w;
+ }
+ }
+ # Filename
+ $w = $strlen;
+ $format = "%-${w}s|";
+ $heading1 = sprintf("%*s|", $w, "");
+ $heading2 = sprintf("%-*s|", $w, "Filename");
+ $barlen = $w + 1;
+ # Line coverage rate
+ $w = $fwidth[$F_LN_RATE];
+ $format .= "%${w}s ";
+ $heading1 .= sprintf("%-*s |", $w + $fwidth[$F_LN_NUM],
+ "Lines");
+ $heading2 .= sprintf("%-*s ", $w, "Rate");
+ $barlen += $w + 1;
+ # Number of lines
+ $w = $fwidth[$F_LN_NUM];
+ $format .= "%${w}s|";
+ $heading2 .= sprintf("%*s|", $w, "Num");
+ $barlen += $w + 1;
+ # Function coverage rate
+ $w = $fwidth[$F_FN_RATE];
+ $format .= "%${w}s ";
+ $heading1 .= sprintf("%-*s|", $w + $fwidth[$F_FN_NUM] + 1,
+ "Functions");
+ $heading2 .= sprintf("%-*s ", $w, "Rate");
+ $barlen += $w + 1;
+ # Number of functions
+ $w = $fwidth[$F_FN_NUM];
+ $format .= "%${w}s|";
+ $heading2 .= sprintf("%*s|", $w, "Num");
+ $barlen += $w + 1;
+ # Branch coverage rate
+ $w = $fwidth[$F_BR_RATE];
+ $format .= "%${w}s ";
+ $heading1 .= sprintf("%-*s", $w + $fwidth[$F_BR_NUM] + 1,
+ "Branches");
+ $heading2 .= sprintf("%-*s ", $w, "Rate");
+ $barlen += $w + 1;
+ # Number of branches
+ $w = $fwidth[$F_BR_NUM];
+ $format .= "%${w}s";
+ $heading2 .= sprintf("%*s", $w, "Num");
+ $barlen += $w;
+ # Line end
+ $format .= "\n";
+ $heading1 .= "\n";
+ $heading2 .= "\n";
+
+ # Print heading
+ print($heading1);
+ print($heading2);
+ print(("="x$barlen)."\n");
+
+ # Print per file information
foreach $filename (sort(keys(%{$data})))
{
+ my @file_data;
+ my $print_filename = $filename;
+
$entry = $data->{$filename};
- (undef, undef, undef, undef, $found, $hit) =
+ if (!$opt_list_full_path) {
+ my $p;
+
+ $print_filename = $filename;
+ if (!$got_prefix || !$root_prefix &&
+ !($print_filename =~ s/^\Q$prefix\/\E//)) {
+ my ($v, $d, $f) = splitpath($filename);
+
+ $p = catpath($v, $d, "");
+ $p =~ s/\/$//;
+ $print_filename = $f;
+ } else {
+ $p = $prefix;
+ }
+
+ if (!defined($lastpath) || $lastpath ne $p) {
+ print("\n") if (defined($lastpath));
+ $lastpath = $p;
+ print("[$lastpath/]\n") if (!$root_prefix);
+ }
+ $print_filename = shorten_filename($print_filename,
+ $strlen);
+ }
+
+ (undef, undef, undef, undef, undef, undef, undef, undef,
+ $found, $hit, $fn_found, $fn_hit, $br_found, $br_hit) =
get_info_entry($entry);
- printf("$filename: $hit of $found lines hit\n");
+
+ # Assume zero count if there is no function data for this file
+ if (!defined($fn_found) || !defined($fn_hit)) {
+ $fn_found = 0;
+ $fn_hit = 0;
+ }
+ # Assume zero count if there is no branch data for this file
+ if (!defined($br_found) || !defined($br_hit)) {
+ $br_found = 0;
+ $br_hit = 0;
+ }
+
+ # Add line coverage totals
+ $total_found += $found;
+ $total_hit += $hit;
+ # Add function coverage totals
+ $fn_total_found += $fn_found;
+ $fn_total_hit += $fn_hit;
+ # Add branch coverage totals
+ $br_total_found += $br_found;
+ $br_total_hit += $br_hit;
+
+ # Determine line coverage rate for this file
+ if ($found == 0) {
+ $rate = "-";
+ } else {
+ $rate = shorten_rate(100 * $hit / $found,
+ $fwidth[$F_LN_RATE]);
+ }
+ # Determine function coverage rate for this file
+ if (!defined($fn_found) || $fn_found == 0) {
+ $fnrate = "-";
+ } else {
+ $fnrate = shorten_rate(100 * $fn_hit / $fn_found,
+ $fwidth[$F_FN_RATE]);
+ }
+ # Determine branch coverage rate for this file
+ if (!defined($br_found) || $br_found == 0) {
+ $brrate = "-";
+ } else {
+ $brrate = shorten_rate(100 * $br_hit / $br_found,
+ $fwidth[$F_BR_RATE]);
+ }
+
+ # Assemble line parameters
+ push(@file_data, $print_filename);
+ push(@file_data, $rate);
+ push(@file_data, shorten_number($found, $fwidth[$F_LN_NUM]));
+ push(@file_data, $fnrate);
+ push(@file_data, shorten_number($fn_found, $fwidth[$F_FN_NUM]));
+ push(@file_data, $brrate);
+ push(@file_data, shorten_number($br_found, $fwidth[$F_BR_NUM]));
+
+ # Print assembled line
+ printf($format, @file_data);
}
+
+ # Determine total line coverage rate
+ if ($total_found == 0) {
+ $rate = "-";
+ } else {
+ $rate = shorten_rate(100 * $total_hit / $total_found,
+ $fwidth[$F_LN_RATE]);
+ }
+ # Determine total function coverage rate
+ if ($fn_total_found == 0) {
+ $fnrate = "-";
+ } else {
+ $fnrate = shorten_rate(100 * $fn_total_hit / $fn_total_found,
+ $fwidth[$F_FN_RATE]);
+ }
+ # Determine total branch coverage rate
+ if ($br_total_found == 0) {
+ $brrate = "-";
+ } else {
+ $brrate = shorten_rate(100 * $br_total_hit / $br_total_found,
+ $fwidth[$F_BR_RATE]);
+ }
+
+ # Print separator
+ print(("="x$barlen)."\n");
+
+ # Assemble line parameters
+ push(@footer, sprintf("%*s", $strlen, "Total:"));
+ push(@footer, $rate);
+ push(@footer, shorten_number($total_found, $fwidth[$F_LN_NUM]));
+ push(@footer, $fnrate);
+ push(@footer, shorten_number($fn_total_found, $fwidth[$F_FN_NUM]));
+ push(@footer, $brrate);
+ push(@footer, shorten_number($br_total_found, $fwidth[$F_BR_NUM]));
+
+ # Print assembled line
+ printf($format, @footer);
}
@@ -1863,7 +3413,7 @@
# Transform all other lines which come after the last diff entry
foreach (sort({$a <=> $b} keys(%{$count_data})))
{
- if ($_ < $last_old)
+ if ($_ <= $last_old)
{
# Skip lines which were covered by line hash
next;
@@ -1877,9 +3427,91 @@
#
+# apply_diff_to_brcount(brcount, linedata)
+#
+# Adjust line numbers of branch coverage data according to linedata.
+#
+
+sub apply_diff_to_brcount($$)
+{
+ my ($brcount, $linedata) = @_;
+ my $db;
+
+ # Convert brcount to db format
+ $db = brcount_to_db($brcount);
+ # Apply diff to db format
+ $db = apply_diff($db, $linedata);
+ # Convert db format back to brcount format
+ ($brcount) = db_to_brcount($db);
+
+ return $brcount;
+}
+
+
+#
+# get_hash_max(hash_ref)
+#
+# Return the highest integer key from hash.
+#
+
+sub get_hash_max($)
+{
+ my ($hash) = @_;
+ my $max;
+
+ foreach (keys(%{$hash})) {
+ if (!defined($max)) {
+ $max = $_;
+ } elsif ($hash->{$_} > $max) {
+ $max = $_;
+ }
+ }
+ return $max;
+}
+
+sub get_hash_reverse($)
+{
+ my ($hash) = @_;
+ my %result;
+
+ foreach (keys(%{$hash})) {
+ $result{$hash->{$_}} = $_;
+ }
+
+ return \%result;
+}
+
+#
+# apply_diff_to_funcdata(funcdata, line_hash)
+#
+
+sub apply_diff_to_funcdata($$)
+{
+ my ($funcdata, $linedata) = @_;
+ my $last_new = get_hash_max($linedata);
+ my $last_old = $linedata->{$last_new};
+ my $func;
+ my %result;
+ my $line_diff = get_hash_reverse($linedata);
+
+ foreach $func (keys(%{$funcdata})) {
+ my $line = $funcdata->{$func};
+
+ if (defined($line_diff->{$line})) {
+ $result{$func} = $line_diff->{$line};
+ } elsif ($line > $last_old) {
+ $result{$func} = $line + $last_new - $last_old;
+ }
+ }
+
+ return \%result;
+}
+
+
+#
# get_line_hash($filename, $diff_data, $path_data)
#
-# Find line hash in DIFF_DATA which matches FILENAME. On succes, return list
+# Find line hash in DIFF_DATA which matches FILENAME. On success, return list
# line hash. or undef in case of no match. Die if more than one line hashes in
# DIFF_DATA match.
#
@@ -1897,10 +3529,16 @@
my $old_depth;
my $new_depth;
+ # Remove trailing slash from diff path
+ $diff_path =~ s/\/$//;
foreach (keys(%{$diff_data}))
{
+ my $sep = "";
+
+ $sep = '/' if (!/^\//);
+
# Try to match diff filename with filename
- if ($filename =~ /^\Q$diff_path\E\/$_$/)
+ if ($filename =~ /^\Q$diff_path$sep$_\E$/)
{
if ($diff_name)
{
@@ -2013,6 +3651,63 @@
}
}
+#
+# sub adjust_fncdata(funcdata, testfncdata, sumfnccount)
+#
+# Remove function call count data from testfncdata and sumfnccount which
+# is no longer present in funcdata.
+#
+
+sub adjust_fncdata($$$)
+{
+ my ($funcdata, $testfncdata, $sumfnccount) = @_;
+ my $testname;
+ my $func;
+ my $f_found;
+ my $f_hit;
+
+ # Remove count data in testfncdata for functions which are no longer
+ # in funcdata
+ foreach $testname (%{$testfncdata}) {
+ my $fnccount = $testfncdata->{$testname};
+
+ foreach $func (%{$fnccount}) {
+ if (!defined($funcdata->{$func})) {
+ delete($fnccount->{$func});
+ }
+ }
+ }
+ # Remove count data in sumfnccount for functions which are no longer
+ # in funcdata
+ foreach $func (%{$sumfnccount}) {
+ if (!defined($funcdata->{$func})) {
+ delete($sumfnccount->{$func});
+ }
+ }
+}
+
+#
+# get_func_found_and_hit(sumfnccount)
+#
+# Return (f_found, f_hit) for sumfnccount
+#
+
+sub get_func_found_and_hit($)
+{
+ my ($sumfnccount) = @_;
+ my $function;
+ my $f_found;
+ my $f_hit;
+
+ $f_found = scalar(keys(%{$sumfnccount}));
+ $f_hit = 0;
+ foreach $function (keys(%{$sumfnccount})) {
+ if ($sumfnccount->{$function} > 0) {
+ $f_hit++;
+ }
+ }
+ return ($f_found, $f_hit);
+}
#
# diff()
@@ -2035,10 +3730,19 @@
my $sumcount;
my $funcdata;
my $checkdata;
+ my $testfncdata;
+ my $sumfnccount;
+ my $testbrdata;
+ my $sumbrcount;
my $found;
my $hit;
+ my $f_found;
+ my $f_hit;
+ my $br_found;
+ my $br_hit;
my $converted = 0;
my $unchanged = 0;
+ my @result;
local *INFO_HANDLE;
($diff_data, $path_data) = read_diff($ARGV[0]);
@@ -2068,17 +3772,25 @@
}
info("Converting $filename\n");
$entry = $trace_data->{$filename};
- ($testdata, $sumcount, $funcdata, $checkdata) =
+ ($testdata, $sumcount, $funcdata, $checkdata, $testfncdata,
+ $sumfnccount, $testbrdata, $sumbrcount) =
get_info_entry($entry);
# Convert test data
foreach $testname (keys(%{$testdata}))
{
+ # Adjust line numbers of line coverage data
$testdata->{$testname} =
apply_diff($testdata->{$testname}, $line_hash);
+ # Adjust line numbers of branch coverage data
+ $testbrdata->{$testname} =
+ apply_diff_to_brcount($testbrdata->{$testname},
+ $line_hash);
# Remove empty sets of test data
if (scalar(keys(%{$testdata->{$testname}})) == 0)
{
delete($testdata->{$testname});
+ delete($testfncdata->{$testname});
+ delete($testbrdata->{$testname});
}
}
# Rename test data to indicate conversion
@@ -2097,16 +3809,43 @@
$testdata->{$testname},
$testdata->{$testname.",diff"});
delete($testdata->{$testname.",diff"});
+ # Add function call counts
+ ($testfncdata->{$testname}) = add_fnccount(
+ $testfncdata->{$testname},
+ $testfncdata->{$testname.",diff"});
+ delete($testfncdata->{$testname.",diff"});
+ # Add branch counts
+ ($testbrdata->{$testname}) = combine_brcount(
+ $testbrdata->{$testname},
+ $testbrdata->{$testname.",diff"},
+ $BR_ADD);
+ delete($testbrdata->{$testname.",diff"});
}
+ # Move test data to new testname
$testdata->{$testname.",diff"} = $testdata->{$testname};
delete($testdata->{$testname});
+ # Move function call count data to new testname
+ $testfncdata->{$testname.",diff"} =
+ $testfncdata->{$testname};
+ delete($testfncdata->{$testname});
+ # Move branch count data to new testname
+ $testbrdata->{$testname.",diff"} =
+ $testbrdata->{$testname};
+ delete($testbrdata->{$testname});
}
# Convert summary of test data
$sumcount = apply_diff($sumcount, $line_hash);
# Convert function data
- $funcdata = apply_diff($funcdata, $line_hash);
+ $funcdata = apply_diff_to_funcdata($funcdata, $line_hash);
+ # Convert branch coverage data
+ $sumbrcount = apply_diff_to_brcount($sumbrcount, $line_hash);
+ # Update found/hit numbers
# Convert checksum data
$checkdata = apply_diff($checkdata, $line_hash);
+ # Convert function call count data
+ adjust_fncdata($funcdata, $testfncdata, $sumfnccount);
+ ($f_found, $f_hit) = get_func_found_and_hit($sumfnccount);
+ ($br_found, $br_hit) = get_br_found_and_hit($sumbrcount);
# Update found/hit numbers
$found = 0;
$hit = 0;
@@ -2122,7 +3861,9 @@
{
# Store converted entry
set_info_entry($entry, $testdata, $sumcount, $funcdata,
- $checkdata, $found, $hit);
+ $checkdata, $testfncdata, $sumfnccount,
+ $testbrdata, $sumbrcount, $found, $hit,
+ $f_found, $f_hit, $br_found, $br_hit);
}
else
{
@@ -2147,13 +3888,15 @@
info("Writing data to $output_filename\n");
open(INFO_HANDLE, ">$output_filename")
or die("ERROR: cannot write to $output_filename!\n");
- write_info_file(*INFO_HANDLE, $trace_data);
+ @result = write_info_file(*INFO_HANDLE, $trace_data);
close(*INFO_HANDLE);
}
else
{
- write_info_file(*STDOUT, $trace_data);
+ @result = write_info_file(*STDOUT, $trace_data);
}
+
+ return @result;
}
@@ -2269,3 +4012,164 @@
}
}
}
+
+sub warn_handler($)
+{
+ my ($msg) = @_;
+
+ temp_cleanup();
+ warn("$tool_name: $msg");
+}
+
+sub die_handler($)
+{
+ my ($msg) = @_;
+
+ temp_cleanup();
+ die("$tool_name: $msg");
+}
+
+sub abort_handler($)
+{
+ temp_cleanup();
+ exit(1);
+}
+
+sub temp_cleanup()
+{
+ if (@temp_dirs) {
+ info("Removing temporary directories.\n");
+ foreach (@temp_dirs) {
+ rmtree($_);
+ }
+ @temp_dirs = ();
+ }
+}
+
+sub setup_gkv_sys()
+{
+ system_no_output(3, "mount", "-t", "debugfs", "nodev",
+ "/sys/kernel/debug");
+}
+
+sub setup_gkv_proc()
+{
+ if (system_no_output(3, "modprobe", "gcov_proc")) {
+ system_no_output(3, "modprobe", "gcov_prof");
+ }
+}
+
+sub check_gkv_sys($)
+{
+ my ($dir) = @_;
+
+ if (-e "$dir/reset") {
+ return 1;
+ }
+ return 0;
+}
+
+sub check_gkv_proc($)
+{
+ my ($dir) = @_;
+
+ if (-e "$dir/vmlinux") {
+ return 1;
+ }
+ return 0;
+}
+
+sub setup_gkv()
+{
+ my $dir;
+ my $sys_dir = "/sys/kernel/debug/gcov";
+ my $proc_dir = "/proc/gcov";
+ my @todo;
+
+ if (!defined($gcov_dir)) {
+ info("Auto-detecting gcov kernel support.\n");
+ @todo = ( "cs", "cp", "ss", "cs", "sp", "cp" );
+ } elsif ($gcov_dir =~ /proc/) {
+ info("Checking gcov kernel support at $gcov_dir ".
+ "(user-specified).\n");
+ @todo = ( "cp", "sp", "cp", "cs", "ss", "cs");
+ } else {
+ info("Checking gcov kernel support at $gcov_dir ".
+ "(user-specified).\n");
+ @todo = ( "cs", "ss", "cs", "cp", "sp", "cp", );
+ }
+ foreach (@todo) {
+ if ($_ eq "cs") {
+ # Check /sys
+ $dir = defined($gcov_dir) ? $gcov_dir : $sys_dir;
+ if (check_gkv_sys($dir)) {
+ info("Found ".$GKV_NAME[$GKV_SYS]." gcov ".
+ "kernel support at $dir\n");
+ return ($GKV_SYS, $dir);
+ }
+ } elsif ($_ eq "cp") {
+ # Check /proc
+ $dir = defined($gcov_dir) ? $gcov_dir : $proc_dir;
+ if (check_gkv_proc($dir)) {
+ info("Found ".$GKV_NAME[$GKV_PROC]." gcov ".
+ "kernel support at $dir\n");
+ return ($GKV_PROC, $dir);
+ }
+ } elsif ($_ eq "ss") {
+ # Setup /sys
+ setup_gkv_sys();
+ } elsif ($_ eq "sp") {
+ # Setup /proc
+ setup_gkv_proc();
+ }
+ }
+ if (defined($gcov_dir)) {
+ die("ERROR: could not find gcov kernel data at $gcov_dir\n");
+ } else {
+ die("ERROR: no gcov kernel data found\n");
+ }
+}
+
+
+#
+# get_overall_line(found, hit, name_singular, name_plural)
+#
+# Return a string containing overall information for the specified
+# found/hit data.
+#
+
+sub get_overall_line($$$$)
+{
+ my ($found, $hit, $name_sn, $name_pl) = @_;
+ my $name;
+
+ return "no data found" if (!defined($found) || $found == 0);
+ $name = ($found == 1) ? $name_sn : $name_pl;
+ return sprintf("%.1f%% (%d of %d %s)", $hit * 100 / $found, $hit,
+ $found, $name);
+}
+
+
+#
+# print_overall_rate(ln_do, ln_found, ln_hit, fn_do, fn_found, fn_hit, br_do
+# br_found, br_hit)
+#
+# Print overall coverage rates for the specified coverage types.
+#
+
+sub print_overall_rate($$$$$$$$$)
+{
+ my ($ln_do, $ln_found, $ln_hit, $fn_do, $fn_found, $fn_hit,
+ $br_do, $br_found, $br_hit) = @_;
+
+ info("Overall coverage rate:\n");
+ info(" lines......: %s\n",
+ get_overall_line($ln_found, $ln_hit, "line", "lines"))
+ if ($ln_do);
+ info(" functions..: %s\n",
+ get_overall_line($fn_found, $fn_hit, "function", "functions"))
+ if ($fn_do);
+ info(" branches...: %s\n",
+ get_overall_line($br_found, $br_hit, "branch", "branches"))
+ if ($br_do);
+}
--- a/utils/print-introspected-doxygen.cc Sat Aug 20 14:41:19 2011 -0400
+++ b/utils/print-introspected-doxygen.cc Mon Oct 17 16:59:17 2011 -0400
@@ -1,5 +1,6 @@
#include <iostream>
#include <algorithm>
+#include <map>
#include "ns3/object.h"
#include "ns3/pointer.h"
#include "ns3/object-vector.h"
@@ -13,26 +14,55 @@
NS_LOG_COMPONENT_DEFINE ("PrintIntrospectedDoxygen");
+namespace
+{
+ std::string anchor;
+ std::string boldStart;
+ std::string boldStop;
+ std::string breakBoth;
+ std::string breakHtmlOnly;
+ std::string breakTextOnly;
+ std::string brief;
+ std::string commentStart;
+ std::string commentStop;
+ std::string defgroupAttributeListStart;
+ std::string defgroupAttributeListStop;
+ std::string defgroupGlobalValueListStart;
+ std::string defgroupGlobalValueListStop;
+ std::string defgroupTraceSourceListStart;
+ std::string defgroupTraceSourceListStop;
+ std::string functionStart;
+ std::string functionStop;
+ std::string indentHtmlOnly;
+ std::string ingroupConstructs;
+ std::string listStart;
+ std::string listStop;
+ std::string listLineStart;
+ std::string listLineStop;
+ std::string reference;
+
+} // anonymous namespace
+
void
PrintAttributes (TypeId tid, std::ostream &os)
{
- os << "<ul>"<<std::endl;
+ os << listStart << std::endl;
for (uint32_t j = 0; j < tid.GetAttributeN (); j++)
{
struct TypeId::AttributeInformation info = tid.GetAttribute(j);
- os << "<li><b>" << info.name << "</b>: "
+ os << listLineStart << boldStart << info.name << boldStop << ": "
<< info.help << std::endl;
- os << " <ul>" << std::endl
- << " <li>Set with class: \\ref " << info.checker->GetValueTypeName () << "</li>" << std::endl;
+ os << " " << listStart << std::endl
+ << " " << listLineStart << "Set with class: " << reference << info.checker->GetValueTypeName () << listLineStop << std::endl;
if (info.checker->HasUnderlyingTypeInformation ())
{
- os << " <li>Underlying type: \\ref " << info.checker->GetUnderlyingTypeInformation () << "</li>" << std::endl;
+ os << " " << listLineStart << "Underlying type: " << reference << info.checker->GetUnderlyingTypeInformation () << listLineStop << std::endl;
}
if (info.flags & TypeId::ATTR_CONSTRUCT && info.accessor->HasSetter ())
{
- os << " <li>Initial value: " << info.initialValue->SerializeToString (info.checker) << "</li>" << std::endl;
+ os << " " << listLineStart << "Initial value: " << info.initialValue->SerializeToString (info.checker) << listLineStop << std::endl;
}
- os << " <li>Flags: ";
+ os << " " << listLineStart << "Flags: ";
if (info.flags & TypeId::ATTR_CONSTRUCT && info.accessor->HasSetter ())
{
os << "construct ";
@@ -45,26 +75,26 @@
{
os << "read ";
}
- os << "</li>" << std::endl;
- os << " </ul> " << std::endl;
+ os << listLineStop << std::endl;
+ os << " " << listStop << " " << std::endl;
}
- os << "</ul>" << std::endl;
+ os << listStop << std::endl;
}
void
PrintTraceSources (TypeId tid, std::ostream &os)
{
- os << "<ul>"<<std::endl;
+ os << listStart << std::endl;
for (uint32_t i = 0; i < tid.GetTraceSourceN (); ++i)
{
struct TypeId::TraceSourceInformation info = tid.GetTraceSource (i);
- os << "<li><b>" << info.name << "</b>: "
+ os << listLineStart << boldStart << info.name << boldStop << ": "
<< info.help
<< std::endl;
- os << "</li>" << std::endl;
+ os << listLineStop << std::endl;
}
- os << "</ul>"<<std::endl;
+ os << listStop << std::endl;
}
@@ -259,8 +289,100 @@
}
}
+void
+PrintHelp (const char *program_name)
+{
+ std::cout << "Usage: " << program_name << " [options]" << std::endl
+ << std::endl
+ << "Options:" << std::endl
+ << " --help : print these options" << std::endl
+ << " --output-text : format output as plain text" << std::endl;
+}
+
int main (int argc, char *argv[])
{
+ bool outputText = false;
+ char *programName = argv[0];
+
+ argv++;
+
+ while (*argv != 0)
+ {
+ char *arg = *argv;
+
+ if (strcmp (arg, "--help") == 0)
+ {
+ PrintHelp (programName);
+ return 0;
+ }
+ else if (strcmp(arg, "--output-text") == 0)
+ {
+ outputText = true;
+ }
+ else
+ {
+ // un-recognized command-line argument
+ PrintHelp (programName);
+ return 0;
+ }
+ argv++;
+ }
+
+ if (outputText)
+ {
+ anchor = "";
+ boldStart = "";
+ boldStop = "";
+ breakBoth = "\n";
+ breakHtmlOnly = "";
+ breakTextOnly = "\n";
+ brief = "";
+ commentStart = "===============================================================\n";
+ commentStop = "";
+ defgroupAttributeListStart = "";
+ defgroupAttributeListStop = "\n";
+ defgroupGlobalValueListStart = "";
+ defgroupGlobalValueListStop = "";
+ defgroupTraceSourceListStart = "";
+ defgroupTraceSourceListStop = "\n";
+ functionStart = "";
+ functionStop = "\n\n";
+ indentHtmlOnly = "";
+ ingroupConstructs = "";
+ listStart = "";
+ listStop = "";
+ listLineStart = " * ";
+ listLineStop = "";
+ reference = "";
+ }
+ else
+ {
+ anchor = "\\anchor ";
+ boldStart = "<b>";
+ boldStop = "</b>";
+ breakBoth = "<br>";
+ breakHtmlOnly = "<br>";
+ breakTextOnly = "";
+ brief = "\\brief ";
+ commentStart = "/*!";
+ commentStop = "*/";
+ defgroupAttributeListStart = "\\defgroup AttributeList ";
+ defgroupAttributeListStop = "";
+ defgroupGlobalValueListStart = "\\defgroup GlobalValueList ";
+ defgroupGlobalValueListStop = "";
+ defgroupTraceSourceListStart = "\\defgroup TraceSourceList ";
+ defgroupTraceSourceListStop = "";
+ functionStart = "\\fn ";
+ functionStop = "";
+ indentHtmlOnly = " ";
+ ingroupConstructs = "\\ingroup constructs\n";
+ listStart = "<ul>";
+ listStop = "</ul>";
+ listLineStart = "<li>";
+ listLineStop = "</li>";
+ reference = "\\ref ";
+ }
+
NodeContainer c; c.Create (1);
StaticInformation info;
@@ -278,37 +400,67 @@
info.Gather (object->GetInstanceTypeId ());
}
+ std::map< std::string, uint32_t> nameMap;
+ std::map< std::string, uint32_t>::const_iterator nameMapIterator;
+
+ // Create a map from the class names to their index in the vector of
+ // TypeId's so that the names will end up in alphabetical order.
for (uint32_t i = 0; i < TypeId::GetRegisteredN (); i++)
{
- std::cout << "/*!" << std::endl;
TypeId tid = TypeId::GetRegistered (i);
if (tid.MustHideFromDocumentation ())
{
continue;
}
- std::cout << "\\fn static TypeId " << tid.GetName () << "::GetTypeId (void)" << std::endl;
- std::cout << "\\brief This method returns the TypeId associated to \\ref " << tid.GetName ()
+
+ // Capitalize all of letters in the name so that it sorts
+ // correctly in the map.
+ std::string name = tid.GetName ();
+ for (uint32_t j = 0; j < name.length (); j++)
+ {
+ name[j] = toupper (name[j]);
+ }
+
+ // Save this name's index.
+ nameMap[name] = i;
+ }
+
+ // Iterate over the map, which will print the class names in
+ // alphabetical order.
+ for (nameMapIterator = nameMap.begin (); nameMapIterator != nameMap.end (); nameMapIterator++)
+ {
+ // Get the class's index out of the map;
+ uint32_t i = nameMapIterator->second;
+
+ std::cout << commentStart << std::endl;
+ TypeId tid = TypeId::GetRegistered (i);
+ if (tid.MustHideFromDocumentation ())
+ {
+ continue;
+ }
+ std::cout << functionStart << "static TypeId " << tid.GetName () << "::GetTypeId (void)" << functionStop << std::endl;
+ std::cout << brief << "This method returns the TypeId associated to " << reference << tid.GetName () << "."
<< std::endl << std::endl;
std::vector<std::string> paths = info.Get (tid);
if (!paths.empty ())
{
std::cout << "This object is accessible through the following paths with Config::Set and Config::Connect:"
<< std::endl;
- std::cout << "<ul>" << std::endl;
+ std::cout << listStart << std::endl;
for (uint32_t k = 0; k < paths.size (); ++k)
{
std::string path = paths[k];
- std::cout << "<li>" << path << "</li>" << std::endl;
+ std::cout << listLineStart << path << listLineStop << breakTextOnly << std::endl;
}
- std::cout << "</ul>" << std::endl;
+ std::cout << listStop << std::endl;
}
if (tid.GetAttributeN () == 0)
{
- std::cout << "No Attributes defined for this type.<br>" << std::endl;
+ std::cout << "No Attributes defined for this type." << breakBoth << std::endl;
}
else
{
- std::cout << "Attributes defined for this type:<br>" << std::endl;
+ std::cout << "Attributes defined for this type:" << breakHtmlOnly << std::endl;
PrintAttributes (tid, std::cout);
}
{
@@ -317,7 +469,7 @@
{
if (tmp.GetAttributeN () != 0)
{
- std::cout << "Attributes defined in parent class " << tmp.GetName () << ":<br>" << std::endl;
+ std::cout << "Attributes defined in parent class " << tmp.GetName () << ":" << breakHtmlOnly << std::endl;
PrintAttributes (tmp, std::cout);
}
tmp = tmp.GetParent ();
@@ -325,11 +477,11 @@
}
if (tid.GetTraceSourceN () == 0)
{
- std::cout << "No TraceSources defined for this type.<br>" << std::endl;
+ std::cout << "No TraceSources defined for this type." << breakBoth << std::endl;
}
else
{
- std::cout << "TraceSources defined for this type:<br>" << std::endl;
+ std::cout << "TraceSources defined for this type:" << breakHtmlOnly << std::endl;
PrintTraceSources (tid, std::cout);
}
{
@@ -338,19 +490,19 @@
{
if (tmp.GetTraceSourceN () != 0)
{
- std::cout << "TraceSources defined in parent class " << tmp.GetName () << ":<br>" << std::endl;
+ std::cout << "TraceSources defined in parent class " << tmp.GetName () << ":" << breakHtmlOnly << std::endl;
PrintTraceSources (tmp, std::cout);
}
tmp = tmp.GetParent ();
}
}
- std::cout << "*/" << std::endl;
+ std::cout << commentStop << std::endl;
}
- std::cout << "/*!" << std::endl
- << "\\ingroup constructs" << std::endl
- << "\\defgroup TraceSourceList The list of all trace sources." << std::endl;
+ std::cout << commentStart << std::endl
+ << ingroupConstructs
+ << defgroupTraceSourceListStart << "The list of all trace sources." << defgroupTraceSourceListStop << std::endl;
for (uint32_t i = 0; i < TypeId::GetRegisteredN (); ++i)
{
TypeId tid = TypeId::GetRegistered (i);
@@ -359,21 +511,20 @@
{
continue;
}
- std::cout << "<b>" << tid.GetName () << "</b><br>" << std::endl
- << "<ul>" << std::endl;
+ std::cout << boldStart << tid.GetName () << boldStop << breakHtmlOnly << std::endl
+ << listStart << std::endl;
for (uint32_t j = 0; j < tid.GetTraceSourceN (); ++j)
{
struct TypeId::TraceSourceInformation info = tid.GetTraceSource(j);
- std::cout << "<li>" << info.name << ": " << info.help << "</li>" << std::endl;
+ std::cout << listLineStart << info.name << ": " << info.help << listLineStop << std::endl;
}
- std::cout << "</ul>" << std::endl;
+ std::cout << listStop << std::endl;
}
- std::cout << "*/" << std::endl;
-
+ std::cout << commentStop << std::endl;
- std::cout << "/*!" << std::endl
- << "\\ingroup constructs" << std::endl
- << "\\defgroup AttributeList The list of all attributes." << std::endl;
+ std::cout << commentStart << std::endl
+ << ingroupConstructs
+ << defgroupAttributeListStart << "The list of all attributes." << defgroupAttributeListStop << std::endl;
for (uint32_t i = 0; i < TypeId::GetRegisteredN (); ++i)
{
TypeId tid = TypeId::GetRegistered (i);
@@ -382,31 +533,31 @@
{
continue;
}
- std::cout << "<b>" << tid.GetName () << "</b><br>" << std::endl
- << "<ul>" << std::endl;
+ std::cout << boldStart << tid.GetName () << boldStop << breakHtmlOnly << std::endl
+ << listStart << std::endl;
for (uint32_t j = 0; j < tid.GetAttributeN (); ++j)
{
struct TypeId::AttributeInformation info = tid.GetAttribute(j);
- std::cout << "<li>" << info.name << ": " << info.help << "</li>" << std::endl;
+ std::cout << listLineStart << info.name << ": " << info.help << listLineStop << std::endl;
}
- std::cout << "</ul>" << std::endl;
+ std::cout << listStop << std::endl;
}
- std::cout << "*/" << std::endl;
+ std::cout << commentStop << std::endl;
- std::cout << "/*!" << std::endl
- << "\\ingroup constructs" << std::endl
- << "\\defgroup GlobalValueList The list of all global values." << std::endl
- << "<ul>" << std::endl;
+ std::cout << commentStart << std::endl
+ << ingroupConstructs
+ << defgroupGlobalValueListStart << "The list of all global values." << defgroupGlobalValueListStop << std::endl
+ << listStart << std::endl;
for (GlobalValue::Iterator i = GlobalValue::Begin (); i != GlobalValue::End (); ++i)
{
StringValue val;
(*i)->GetValue (val);
- std::cout << " <li><b>\\anchor GlobalValue" << (*i)->GetName () << " " << (*i)->GetName () << "</b>: " << (*i)->GetHelp () << "(" << val.Get () << ")</li>" << std::endl;
+ std::cout << indentHtmlOnly << listLineStart << boldStart << anchor << "GlobalValue" << (*i)->GetName () << " " << (*i)->GetName () << boldStop << ": " << (*i)->GetHelp () << "(" << val.Get () << ")" << listLineStop << std::endl;
}
- std::cout << "</ul>" << std::endl
- << "*/" << std::endl;
+ std::cout << listStop << std::endl
+ << commentStop << std::endl;
return 0;
--- a/utils/wscript Sat Aug 20 14:41:19 2011 -0400
+++ b/utils/wscript Mon Oct 17 16:59:17 2011 -0400
@@ -10,7 +10,7 @@
# Set the libraries the testrunner depends on equal to the list of
# enabled modules plus the list of enabled module test libraries.
- test_runner.uselib_local = [mod+"--lib" for mod in (env['NS3_ENABLED_MODULES'] + env['NS3_ENABLED_MODULE_TEST_LIBRARIES'])]
+ test_runner.use = [mod for mod in (env['NS3_ENABLED_MODULES'] + env['NS3_ENABLED_MODULE_TEST_LIBRARIES'])]
obj = bld.create_ns3_program('bench-simulator', ['core'])
obj.source = 'bench-simulator.cc'
@@ -28,5 +28,5 @@
obj = bld.create_ns3_program('print-introspected-doxygen', ['network'])
obj.source = 'print-introspected-doxygen.cc'
- obj.uselib_local = [mod+"--lib" for mod in env['NS3_ENABLED_MODULES']]
+ obj.use = [mod for mod in env['NS3_ENABLED_MODULES']]
Binary file waf has changed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/waf-tools/boost.py Mon Oct 17 16:59:17 2011 -0400
@@ -0,0 +1,278 @@
+#!/usr/bin/env python
+# encoding: utf-8
+#
+# partially based on boost.py written by Gernot Vormayr
+# written by Ruediger Sonderfeld <ruediger@c-plusplus.de>, 2008
+# modified by Bjoern Michaelsen, 2008
+# modified by Luca Fossati, 2008
+# rewritten for waf 1.5.1, Thomas Nagy, 2008
+# rewritten for waf 1.6.2, Sylvain Rouquette, 2011
+
+'''
+To add the boost tool to the waf file:
+$ ./waf-light --tools=compat15,boost
+ or, if you have waf >= 1.6.2
+$ ./waf update --files=boost
+
+The wscript will look like:
+
+def options(opt):
+ opt.load('compiler_cxx boost')
+
+def configure(conf):
+ conf.load('compiler_cxx boost')
+ conf.check_boost(lib='system filesystem', mt=True, static=True)
+
+def build(bld):
+ bld(source='main.cpp', target='app', use='BOOST')
+'''
+
+import sys
+import re
+from waflib import Utils, Logs
+from waflib.Configure import conf
+from waflib.Errors import WafError
+
+BOOST_LIBS = ('/usr/lib', '/usr/local/lib',
+ '/opt/local/lib', '/sw/lib', '/lib')
+BOOST_INCLUDES = ('/usr/include', '/usr/local/include',
+ '/opt/local/include', '/sw/include')
+BOOST_VERSION_FILE = 'boost/version.hpp'
+BOOST_VERSION_CODE = '''
+#include <iostream>
+#include <boost/version.hpp>
+int main() { std::cout << BOOST_LIB_VERSION << std::endl; }
+'''
+
+# toolsets from {boost_dir}/tools/build/v2/tools/common.jam
+PLATFORM = Utils.unversioned_sys_platform()
+detect_intel = lambda env: (PLATFORM == 'win32') and 'iw' or 'il'
+detect_clang = lambda env: (PLATFORM == 'darwin') and 'clang-darwin' or 'clang'
+detect_mingw = lambda env: (re.search('MinGW', env.CXX[0])) and 'mgw' or 'gcc'
+BOOST_TOOLSETS = {
+ 'borland': 'bcb',
+ 'clang': detect_clang,
+ 'como': 'como',
+ 'cw': 'cw',
+ 'darwin': 'xgcc',
+ 'edg': 'edg',
+ 'g++': detect_mingw,
+ 'gcc': detect_mingw,
+ 'icpc': detect_intel,
+ 'intel': detect_intel,
+ 'kcc': 'kcc',
+ 'kylix': 'bck',
+ 'mipspro': 'mp',
+ 'mingw': 'mgw',
+ 'msvc': 'vc',
+ 'qcc': 'qcc',
+ 'sun': 'sw',
+ 'sunc++': 'sw',
+ 'tru64cxx': 'tru',
+ 'vacpp': 'xlc'
+}
+
+
+def options(opt):
+ opt.add_option('--boost-includes', type='string',
+ default='', dest='boost_includes',
+ help='''path to the boost directory where the includes are
+ e.g. /boost_1_45_0/include''')
+ opt.add_option('--boost-libs', type='string',
+ default='', dest='boost_libs',
+ help='''path to the directory where the boost libs are
+ e.g. /boost_1_45_0/stage/lib''')
+ opt.add_option('--boost-static', action='store_true',
+ default=False, dest='boost_static',
+ help='link static libraries')
+ opt.add_option('--boost-mt', action='store_true',
+ default=False, dest='boost_mt',
+ help='select multi-threaded libraries')
+ opt.add_option('--boost-abi', type='string', default='', dest='boost_abi',
+ help='''select libraries with tags (dgsyp, d for debug),
+ see doc Boost, Getting Started, chapter 6.1''')
+ opt.add_option('--boost-toolset', type='string',
+ default='', dest='boost_toolset',
+ help='force a toolset e.g. msvc, vc90, \
+ gcc, mingw, mgw45 (default: auto)')
+ py_version = '%d%d' % (sys.version_info[0], sys.version_info[1])
+ opt.add_option('--boost-python', type='string',
+ default=py_version, dest='boost_python',
+ help='select the lib python with this version \
+ (default: %s)' % py_version)
+
+
+@conf
+def __boost_get_version_file(self, dir):
+ try:
+ return self.root.find_dir(dir).find_node(BOOST_VERSION_FILE)
+ except:
+ return None
+
+
+@conf
+def boost_get_version(self, dir):
+ """silently retrieve the boost version number"""
+ re_but = re.compile('^#define\\s+BOOST_LIB_VERSION\\s+"(.*)"$', re.M)
+ try:
+ val = re_but.search(self.__boost_get_version_file(dir).read()).group(1)
+ except:
+ val = self.check_cxx(fragment=BOOST_VERSION_CODE, includes=[dir],
+ execute=True, define_ret=True)
+ return val
+
+
+@conf
+def boost_get_includes(self, *k, **kw):
+ includes = k and k[0] or kw.get('includes', None)
+ if includes and self.__boost_get_version_file(includes):
+ return includes
+ for dir in BOOST_INCLUDES:
+ if self.__boost_get_version_file(dir):
+ return dir
+ if includes:
+ self.fatal('headers not found in %s' % includes)
+ else:
+ self.fatal('headers not found, use --boost-includes=/path/to/boost')
+
+
+@conf
+def boost_get_toolset(self, cc):
+ toolset = cc
+ if not cc:
+ build_platform = Utils.unversioned_sys_platform()
+ if build_platform in BOOST_TOOLSETS:
+ cc = build_platform
+ else:
+ cc = self.env.CXX_NAME
+ if cc in BOOST_TOOLSETS:
+ toolset = BOOST_TOOLSETS[cc]
+ return isinstance(toolset, str) and toolset or toolset(self.env)
+
+
+@conf
+def __boost_get_libs_path(self, *k, **kw):
+ ''' return the lib path and all the files in it '''
+ if 'files' in kw:
+ return self.root.find_dir('.'), Utils.to_list(kw['files'])
+ libs = k and k[0] or kw.get('libs', None)
+ if libs:
+ path = self.root.find_dir(libs)
+ files = path.ant_glob('*boost_*')
+ if not libs or not files:
+ for dir in BOOST_LIBS:
+ try:
+ path = self.root.find_dir(dir)
+ files = path.ant_glob('*boost_*')
+ if files:
+ break
+ path = self.root.find_dir(dir + '64')
+ files = path.ant_glob('*boost_*')
+ if files:
+ break
+ except:
+ path = None
+ if not path:
+ if libs:
+ self.fatal('libs not found in %s' % libs)
+ else:
+ self.fatal('libs not found, \
+ use --boost-includes=/path/to/boost/lib')
+ return path, files
+
+
+@conf
+def boost_get_libs(self, *k, **kw):
+ '''
+ return the lib path and the required libs
+ according to the parameters
+ '''
+ path, files = self.__boost_get_libs_path(**kw)
+ t = []
+ if kw.get('mt', False):
+ t.append('mt')
+ if kw.get('abi', None):
+ t.append(kw['abi'])
+ tags = t and '(-%s)+' % '-'.join(t) or ''
+ toolset = '(-%s[0-9]{0,3})+' % self.boost_get_toolset(kw.get('toolset', ''))
+ version = '(-%s)+' % self.env.BOOST_VERSION
+
+ def find_lib(re_lib, files):
+ for file in files:
+ if re_lib.search(file.name):
+ return file
+ return None
+
+ def format_lib_name(name):
+ if name.startswith('lib'):
+ name = name[3:]
+ return name.split('.')[0]
+
+ libs = []
+ for lib in Utils.to_list(k and k[0] or kw.get('lib', None)):
+ py = (lib == 'python') and '(-py%s)+' % kw['python'] or ''
+ # Trying libraries, from most strict match to least one
+ for pattern in ['boost_%s%s%s%s%s' % (lib, toolset, tags, py, version),
+ 'boost_%s%s%s%s' % (lib, tags, py, version),
+ 'boost_%s%s%s' % (lib, tags, version),
+ # Give up trying to find the right version
+ 'boost_%s%s%s%s' % (lib, toolset, tags, py),
+ 'boost_%s%s%s' % (lib, tags, py),
+ 'boost_%s%s' % (lib, tags)]:
+ file = find_lib(re.compile(pattern), files)
+ if file:
+ libs.append(format_lib_name(file.name))
+ break
+ else:
+ self.fatal('lib %s not found in %s' % (lib, path))
+
+ return path.abspath(), libs
+
+
+@conf
+def check_boost(self, *k, **kw):
+ """
+ initialize boost
+
+ You can pass the same parameters as the command line (without "--boost-"),
+ but the command line has the priority.
+ """
+ if not self.env['CXX']:
+ self.fatal('load a c++ compiler first, conf.load("compiler_cxx")')
+
+ params = {'lib': k and k[0] or kw.get('lib', None)}
+ for key, value in self.options.__dict__.items():
+ if not key.startswith('boost_'):
+ continue
+ key = key[len('boost_'):]
+ params[key] = value and value or kw.get(key, '')
+
+ var = kw.get('uselib_store', 'BOOST')
+
+ self.start_msg('Checking boost includes')
+ try:
+ self.env['INCLUDES_%s' % var] = self.boost_get_includes(**params)
+ self.env.BOOST_VERSION = self.boost_get_version(self.env['INCLUDES_%s' % var])
+ except WafError:
+ self.end_msg("not found", 'YELLOW')
+ raise
+ self.end_msg(self.env.BOOST_VERSION)
+ if Logs.verbose:
+ Logs.pprint('CYAN', ' path : %s' % self.env['INCLUDES_%s' % var])
+
+ if not params['lib']:
+ return
+ self.start_msg('Checking boost libs')
+ try:
+ suffix = params.get('static', 'ST') or ''
+ path, libs = self.boost_get_libs(**params)
+ except WafError:
+ self.end_msg("not found", 'YELLOW')
+ raise
+ self.env['%sLIBPATH_%s' % (suffix, var)] = [path]
+ self.env['%sLIB_%s' % (suffix, var)] = libs
+ self.end_msg('ok')
+ if Logs.verbose:
+ Logs.pprint('CYAN', ' path : %s' % path)
+ Logs.pprint('CYAN', ' libs : %s' % libs)
+
--- a/waf-tools/cflags.py Sat Aug 20 14:41:19 2011 -0400
+++ b/waf-tools/cflags.py Mon Oct 17 16:59:17 2011 -0400
@@ -144,7 +144,7 @@
default_profile = 'default'
-def set_options(opt):
+def options(opt):
assert default_profile in profiles
opt.add_option('-d', '--build-profile',
action='store',
@@ -157,7 +157,7 @@
choices=profiles.keys(),
dest='build_profile')
-def detect(conf):
+def configure(conf):
cc = conf.env['COMPILER_CC'] or None
cxx = conf.env['COMPILER_CXX'] or None
if not (cc or cxx):
--- a/waf-tools/command.py Sat Aug 20 14:41:19 2011 -0400
+++ b/waf-tools/command.py Mon Oct 17 16:59:17 2011 -0400
@@ -1,9 +1,10 @@
-from TaskGen import feature, taskgen, before, task_gen
-import Node, Task, Utils, Build, pproc, Constants
+import TaskGen# import feature, taskgen_method, before_method, task_gen
+import Node, Task, Utils, Build
+import subprocess
import Options
import shellcmd
-shellcmd.subprocess = pproc # the WAF version of the subprocess module is supposedly less buggy
+#shellcmd.subprocess = pproc # the WAF version of the subprocess module is supposedly less buggy
from Logs import debug, error
shellcmd.debug = debug
@@ -18,7 +19,7 @@
class command_task(Task.Task):
color = "BLUE"
def __init__(self, env, generator):
- Task.Task.__init__(self, env, normal=1, generator=generator)
+ Task.Task.__init__(self, env=env, normal=1, generator=generator)
def __str__(self):
"string to display to the user"
@@ -33,7 +34,6 @@
pipeline = shellcmd.Pipeline()
pipeline.parse(self.generator.command)
cmd = pipeline.get_abbreviated_command()
-
return 'command (%s): %s%s%s\n' % (cmd, src_str, sep, tgt_str)
def _subst_arg(self, arg, direction, namespace):
@@ -50,21 +50,24 @@
result = eval(var+code, namespace)
if isinstance(result, Node.Node):
if var == 'TGT':
- return result.bldpath(self.env)
+ return result.get_bld().abspath()
elif var == 'SRC':
- return result.srcpath(self.env)
+ return result.srcpath()
else:
raise ValueError("Bad subst variable %r" % var)
elif result is self.inputs:
if len(self.inputs) == 1:
- return result[0].srcpath(self.env)
+ return result[0].srcpath()
else:
raise ValueError("${SRC} requested but have multiple sources; which one?")
elif result is self.outputs:
if len(self.outputs) == 1:
- return result[0].bldpath(self.env)
+ return result[0].get_bld().abspath()
else:
raise ValueError("${TGT} requested but have multiple targets; which one?")
+ elif isinstance(result, list):
+ assert len(result) == 1
+ return result[0]
else:
return result
return None
@@ -95,40 +98,37 @@
cmd.env_vars = env_vars
elif isinstance(cmd, shellcmd.Chdir):
cmd.dir = self._subst_arg(cmd.dir, None, namespace)
-
return pipeline.run(verbose=(Options.options.verbose > 0))
-@taskgen
-@feature('command')
+@TaskGen.taskgen_method
+@TaskGen.feature('command')
def init_command(self):
Utils.def_attrs(self,
- # other variables that can be used in the command: ${VARIABLE}
- variables = None)
+ # other variables that can be used in the command: ${VARIABLE}
+ variables = None,
+ rule='')
-@taskgen
-@feature('command')
-@before('apply_core')
+@TaskGen.feature('command')
+@TaskGen.after_method('process_rule')
def apply_command(self):
- self.meths.remove('apply_core')
+ #self.meths.remove('apply_core')
# create the task
task = self.create_task('command')
setattr(task, "dep_vars", getattr(self, "dep_vars", None))
# process the sources
inputs = []
- for src in self.to_list(self.source):
- node = self.path.find_resource(src)
- if node is None:
- raise Utils.WafError("source %s not found" % src)
- inputs.append(node)
+ for node in self.source:
+ inputs.append(node)
task.set_inputs(inputs)
task.set_outputs([self.path.find_or_declare(tgt) for tgt in self.to_list(self.target)])
+ self.source = ''
#Task.file_deps = Task.extract_deps
-class command_taskgen(task_gen):
- def __init__(self, *k, **kw):
- task_gen.__init__(self, *k, **kw)
- self.features.append('command')
+# class command_taskgen(task_gen):
+# def __init__(self, *k, **kw):
+# task_gen.__init__(self, *k, **kw)
+# self.features.append('command')
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/waf-tools/misc.py Mon Oct 17 16:59:17 2011 -0400
@@ -0,0 +1,416 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2006-2010 (ita)
+
+"""
+This tool is totally deprecated
+
+Try using:
+ .pc.in files for .pc files
+ the feature intltool_in - see demos/intltool
+ make-like rules
+"""
+
+import shutil, re, os
+from waflib import TaskGen, Node, Task, Utils, Build, Errors
+from waflib.TaskGen import feature, after_method, before_method
+from waflib.Logs import debug
+
+def copy_attrs(orig, dest, names, only_if_set=False):
+ """
+ copy class attributes from an object to another
+ """
+ for a in Utils.to_list(names):
+ u = getattr(orig, a, ())
+ if u or not only_if_set:
+ setattr(dest, a, u)
+
+def copy_func(tsk):
+ "Make a file copy. This might be used to make other kinds of file processing (even calling a compiler is possible)"
+ env = tsk.env
+ infile = tsk.inputs[0].abspath()
+ outfile = tsk.outputs[0].abspath()
+ try:
+ shutil.copy2(infile, outfile)
+ except (OSError, IOError):
+ return 1
+ else:
+ if tsk.chmod: os.chmod(outfile, tsk.chmod)
+ return 0
+
+def action_process_file_func(tsk):
+ "Ask the function attached to the task to process it"
+ if not tsk.fun: raise Errors.WafError('task must have a function attached to it for copy_func to work!')
+ return tsk.fun(tsk)
+
+@feature('cmd')
+def apply_cmd(self):
+ "call a command everytime"
+ if not self.fun: raise Errors.WafError('cmdobj needs a function!')
+ tsk = Task.TaskBase()
+ tsk.fun = self.fun
+ tsk.env = self.env
+ self.tasks.append(tsk)
+ tsk.install_path = self.install_path
+
+@feature('copy')
+@before_method('process_source')
+def apply_copy(self):
+ Utils.def_attrs(self, fun=copy_func)
+ self.default_install_path = 0
+
+ lst = self.to_list(self.source)
+ self.meths.remove('process_source')
+
+ for filename in lst:
+ node = self.path.find_resource(filename)
+ if not node: raise Errors.WafError('cannot find input file %s for processing' % filename)
+
+ target = self.target
+ if not target or len(lst)>1: target = node.name
+
+ # TODO the file path may be incorrect
+ newnode = self.path.find_or_declare(target)
+
+ tsk = self.create_task('copy', node, newnode)
+ tsk.fun = self.fun
+ tsk.chmod = getattr(self, 'chmod', Utils.O644)
+
+ if not tsk.env:
+ tsk.debug()
+ raise Errors.WafError('task without an environment')
+
+def subst_func(tsk):
+ "Substitutes variables in a .in file"
+
+ m4_re = re.compile('@(\w+)@', re.M)
+
+ code = tsk.inputs[0].read() #Utils.readf(infile)
+
+ # replace all % by %% to prevent errors by % signs in the input file while string formatting
+ code = code.replace('%', '%%')
+
+ s = m4_re.sub(r'%(\1)s', code)
+
+ env = tsk.env
+ di = getattr(tsk, 'dict', {}) or getattr(tsk.generator, 'dict', {})
+ if not di:
+ names = m4_re.findall(code)
+ for i in names:
+ di[i] = env.get_flat(i) or env.get_flat(i.upper())
+
+ tsk.outputs[0].write(s % di)
+
+@feature('subst')
+@before_method('process_source')
+def apply_subst(self):
+ Utils.def_attrs(self, fun=subst_func)
+ lst = self.to_list(self.source)
+ self.meths.remove('process_source')
+
+ self.dict = getattr(self, 'dict', {})
+
+ for filename in lst:
+ node = self.path.find_resource(filename)
+ if not node: raise Errors.WafError('cannot find input file %s for processing' % filename)
+
+ if self.target:
+ newnode = self.path.find_or_declare(self.target)
+ else:
+ newnode = node.change_ext('')
+
+ try:
+ self.dict = self.dict.get_merged_dict()
+ except AttributeError:
+ pass
+
+ if self.dict and not self.env['DICT_HASH']:
+ self.env = self.env.derive()
+ keys = list(self.dict.keys())
+ keys.sort()
+ lst = [self.dict[x] for x in keys]
+ self.env['DICT_HASH'] = str(Utils.h_list(lst))
+
+ tsk = self.create_task('copy', node, newnode)
+ tsk.fun = self.fun
+ tsk.dict = self.dict
+ tsk.dep_vars = ['DICT_HASH']
+ tsk.chmod = getattr(self, 'chmod', Utils.O644)
+
+ if not tsk.env:
+ tsk.debug()
+ raise Errors.WafError('task without an environment')
+
+####################
+## command-output ####
+####################
+
+class cmd_arg(object):
+ """command-output arguments for representing files or folders"""
+ def __init__(self, name, template='%s'):
+ self.name = name
+ self.template = template
+ self.node = None
+
+class input_file(cmd_arg):
+ def find_node(self, base_path):
+ assert isinstance(base_path, Node.Node)
+ self.node = base_path.find_resource(self.name)
+ if self.node is None:
+ raise Errors.WafError("Input file %s not found in " % (self.name, base_path))
+
+ def get_path(self, env, absolute):
+ if absolute:
+ return self.template % self.node.abspath()
+ else:
+ return self.template % self.node.srcpath()
+
+class output_file(cmd_arg):
+ def find_node(self, base_path):
+ assert isinstance(base_path, Node.Node)
+ self.node = base_path.find_or_declare(self.name)
+ if self.node is None:
+ raise Errors.WafError("Output file %s not found in " % (self.name, base_path))
+
+ def get_path(self, env, absolute):
+ if absolute:
+ return self.template % self.node.abspath()
+ else:
+ return self.template % self.node.bldpath()
+
+class cmd_dir_arg(cmd_arg):
+ def find_node(self, base_path):
+ assert isinstance(base_path, Node.Node)
+ self.node = base_path.find_dir(self.name)
+ if self.node is None:
+ raise Errors.WafError("Directory %s not found in " % (self.name, base_path))
+
+class input_dir(cmd_dir_arg):
+ def get_path(self, dummy_env, dummy_absolute):
+ return self.template % self.node.abspath()
+
+class output_dir(cmd_dir_arg):
+ def get_path(self, env, dummy_absolute):
+ return self.template % self.node.abspath()
+
+
+class command_output(Task.Task):
+ color = "BLUE"
+ def __init__(self, env, command, command_node, command_args, stdin, stdout, cwd, os_env, stderr):
+ Task.Task.__init__(self, env=env)
+ assert isinstance(command, (str, Node.Node))
+ self.command = command
+ self.command_args = command_args
+ self.stdin = stdin
+ self.stdout = stdout
+ self.cwd = cwd
+ self.os_env = os_env
+ self.stderr = stderr
+
+ if command_node is not None: self.dep_nodes = [command_node]
+ self.dep_vars = [] # additional environment variables to look
+
+ def run(self):
+ task = self
+ #assert len(task.inputs) > 0
+
+ def input_path(node, template):
+ if task.cwd is None:
+ return template % node.bldpath()
+ else:
+ return template % node.abspath()
+ def output_path(node, template):
+ fun = node.abspath
+ if task.cwd is None: fun = node.bldpath
+ return template % fun()
+
+ if isinstance(task.command, Node.Node):
+ argv = [input_path(task.command, '%s')]
+ else:
+ argv = [task.command]
+
+ for arg in task.command_args:
+ if isinstance(arg, str):
+ argv.append(arg)
+ else:
+ assert isinstance(arg, cmd_arg)
+ argv.append(arg.get_path(task.env, (task.cwd is not None)))
+
+ if task.stdin:
+ stdin = open(input_path(task.stdin, '%s'))
+ else:
+ stdin = None
+
+ if task.stdout:
+ stdout = open(output_path(task.stdout, '%s'), "w")
+ else:
+ stdout = None
+
+ if task.stderr:
+ stderr = open(output_path(task.stderr, '%s'), "w")
+ else:
+ stderr = None
+
+ if task.cwd is None:
+ cwd = ('None (actually %r)' % os.getcwd())
+ else:
+ cwd = repr(task.cwd)
+ debug("command-output: cwd=%s, stdin=%r, stdout=%r, argv=%r" %
+ (cwd, stdin, stdout, argv))
+
+ if task.os_env is None:
+ os_env = os.environ
+ else:
+ os_env = task.os_env
+ command = Utils.subprocess.Popen(argv, stdin=stdin, stdout=stdout, stderr=stderr, cwd=task.cwd, env=os_env)
+ return command.wait()
+
+@feature('command-output')
+def init_cmd_output(self):
+ Utils.def_attrs(self,
+ stdin = None,
+ stdout = None,
+ stderr = None,
+ # the command to execute
+ command = None,
+
+ # whether it is an external command; otherwise it is assumed
+ # to be an executable binary or script that lives in the
+ # source or build tree.
+ command_is_external = False,
+
+ # extra parameters (argv) to pass to the command (excluding
+ # the command itself)
+ argv = [],
+
+ # dependencies to other objects -> this is probably not what you want (ita)
+ # values must be 'task_gen' instances (not names!)
+ dependencies = [],
+
+ # dependencies on env variable contents
+ dep_vars = [],
+
+ # input files that are implicit, i.e. they are not
+ # stdin, nor are they mentioned explicitly in argv
+ hidden_inputs = [],
+
+ # output files that are implicit, i.e. they are not
+ # stdout, nor are they mentioned explicitly in argv
+ hidden_outputs = [],
+
+ # change the subprocess to this cwd (must use obj.input_dir() or output_dir() here)
+ cwd = None,
+
+ # OS environment variables to pass to the subprocess
+ # if None, use the default environment variables unchanged
+ os_env = None)
+
+@feature('command-output')
+@after_method('init_cmd_output')
+def apply_cmd_output(self):
+ if self.command is None:
+ raise Errors.WafError("command-output missing command")
+ if self.command_is_external:
+ cmd = self.command
+ cmd_node = None
+ else:
+ cmd_node = self.path.find_resource(self.command)
+ assert cmd_node is not None, ('''Could not find command '%s' in source tree.
+Hint: if this is an external command,
+use command_is_external=True''') % (self.command,)
+ cmd = cmd_node
+
+ if self.cwd is None:
+ cwd = None
+ else:
+ assert isinstance(cwd, CmdDirArg)
+ self.cwd.find_node(self.path)
+
+ args = []
+ inputs = []
+ outputs = []
+
+ for arg in self.argv:
+ if isinstance(arg, cmd_arg):
+ arg.find_node(self.path)
+ if isinstance(arg, input_file):
+ inputs.append(arg.node)
+ if isinstance(arg, output_file):
+ outputs.append(arg.node)
+
+ if self.stdout is None:
+ stdout = None
+ else:
+ assert isinstance(self.stdout, str)
+ stdout = self.path.find_or_declare(self.stdout)
+ if stdout is None:
+ raise Errors.WafError("File %s not found" % (self.stdout,))
+ outputs.append(stdout)
+
+ if self.stderr is None:
+ stderr = None
+ else:
+ assert isinstance(self.stderr, str)
+ stderr = self.path.find_or_declare(self.stderr)
+ if stderr is None:
+ raise Errors.WafError("File %s not found" % (self.stderr,))
+ outputs.append(stderr)
+
+ if self.stdin is None:
+ stdin = None
+ else:
+ assert isinstance(self.stdin, str)
+ stdin = self.path.find_resource(self.stdin)
+ if stdin is None:
+ raise Errors.WafError("File %s not found" % (self.stdin,))
+ inputs.append(stdin)
+
+ for hidden_input in self.to_list(self.hidden_inputs):
+ node = self.path.find_resource(hidden_input)
+ if node is None:
+ raise Errors.WafError("File %s not found in dir %s" % (hidden_input, self.path))
+ inputs.append(node)
+
+ for hidden_output in self.to_list(self.hidden_outputs):
+ node = self.path.find_or_declare(hidden_output)
+ if node is None:
+ raise Errors.WafError("File %s not found in dir %s" % (hidden_output, self.path))
+ outputs.append(node)
+
+ if not (inputs or getattr(self, 'no_inputs', None)):
+ raise Errors.WafError('command-output objects must have at least one input file or give self.no_inputs')
+ if not (outputs or getattr(self, 'no_outputs', None)):
+ raise Errors.WafError('command-output objects must have at least one output file or give self.no_outputs')
+
+ cwd = self.bld.variant_dir
+ task = command_output(self.env, cmd, cmd_node, self.argv, stdin, stdout, cwd, self.os_env, stderr)
+ task.generator = self
+ copy_attrs(self, task, 'before after ext_in ext_out', only_if_set=True)
+ self.tasks.append(task)
+
+ task.inputs = inputs
+ task.outputs = outputs
+ task.dep_vars = self.to_list(self.dep_vars)
+
+ for dep in self.dependencies:
+ assert dep is not self
+ dep.post()
+ for dep_task in dep.tasks:
+ task.set_run_after(dep_task)
+
+ if not task.inputs:
+ # the case for svnversion, always run, and update the output nodes
+ task.runnable_status = type(Task.TaskBase.run)(runnable_status, task, task.__class__) # always run
+ task.post_run = type(Task.TaskBase.run)(post_run, task, task.__class__)
+
+ # TODO the case with no outputs?
+
+def post_run(self):
+ for x in self.outputs:
+ x.sig = Utils.h_file(x.abspath())
+
+def runnable_status(self):
+ return self.RUN_ME
+
+Task.task_factory('copy', vars=[], func=action_process_file_func)
+
--- a/waf-tools/pkgconfig.py Sat Aug 20 14:41:19 2011 -0400
+++ b/waf-tools/pkgconfig.py Mon Oct 17 16:59:17 2011 -0400
@@ -3,10 +3,11 @@
import Options
import Configure
-import pproc as subprocess
+import subprocess
import config_c
+import sys
-def detect(conf):
+def configure(conf):
pkg_config = conf.find_program('pkg-config', var='PKG_CONFIG')
if not pkg_config: return
@@ -19,25 +20,31 @@
else:
return False
+ if Options.options.verbose:
+ extra_msg = ' (%s)' % expression
+ else:
+ extra_msg = ''
+
+ conf.start_msg('Checking for pkg-config flags for %s%s' % (uselib_name, extra_msg))
+
argv = [pkg_config, '--cflags', '--libs', expression]
- cmd = subprocess.Popen(argv, stdout=subprocess.PIPE)
- out, dummy = cmd.communicate()
+ cmd = subprocess.Popen(argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ out, err = cmd.communicate()
retval = cmd.wait()
- msg_checking = ("pkg-config flags for %s" % (uselib_name,))
- if Options.options.verbose:
- if retval == 0:
- conf.check_message_custom(msg_checking,
- ('(%s)' % expression), out)
+ conf.to_log('%r: %r (exit code %i)\n%s' % (argv, out, retval, err))
+
+ if retval != 0:
+ conf.end_msg(False)
+ sys.stderr.write(err)
+ else:
+ if Options.options.verbose:
+ conf.end_msg(out)
else:
- conf.check_message(msg_checking, ('(%s)' % expression), False)
- else:
- conf.check_message(msg_checking, '', (retval == 0), '')
- conf.log.write('%r: %r (exit code %i)\n' % (argv, out, retval))
+ conf.end_msg(True)
if retval == 0:
-
- config_c.parse_flags(out, uselib_name, conf.env)
+ conf.parse_flags(out, uselib_name, conf.env)
conf.env[uselib_name] = True
return True
@@ -61,7 +68,7 @@
retval = cmd.wait()
out = out.rstrip() # strip the trailing newline
- msg_checking = ("pkg-config variable %r in %s" % (variable, module,))
+ msg_checking = ("Checking for pkg-config variable %r in %s" % (variable, module,))
conf.check_message_custom(msg_checking, '', out)
conf.log.write('%r: %r (exit code %i)\n' % (argv, out, retval))
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/waf-tools/python.py Mon Oct 17 16:59:17 2011 -0400
@@ -0,0 +1,502 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2007-2010 (ita)
+# Gustavo Carneiro (gjc), 2007
+
+#
+# NS-3 Note: this python tool was added only for including a bug fix:
+# http://code.google.com/p/waf/issues/detail?id=1045
+# Once waf 1.6.8 comes out and ns-3 upgrades to it, this copy of the python tool can be removed
+#
+
+"""
+Support for Python, detect the headers and libraries and provide
+*use* variables to link C/C++ programs against them::
+
+ def options(opt):
+ opt.load('compiler_c python')
+ def configure(conf):
+ conf.load('compiler_c python')
+ conf.check_python_version((2,4,2))
+ conf.check_python_headers()
+ def build(bld):
+ bld.program(features='pyembed', source='a.c', target='myprog')
+ bld.shlib(features='pyext', source='b.c', target='mylib')
+"""
+
+import os, sys
+from waflib import Utils, Options, Errors
+from waflib.Logs import debug, warn, info, error
+from waflib.TaskGen import extension, before_method, after_method, feature
+from waflib.Configure import conf
+
+FRAG = '''
+#include <Python.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void Py_Initialize(void);
+ void Py_Finalize(void);
+#ifdef __cplusplus
+}
+#endif
+int main()
+{
+ Py_Initialize();
+ Py_Finalize();
+ return 0;
+}
+'''
+"""
+Piece of C/C++ code used in :py:func:`waflib.Tools.python.check_python_headers`
+"""
+
+INST = '''
+import sys, py_compile
+py_compile.compile(sys.argv[1], sys.argv[2], sys.argv[3])
+'''
+"""
+Piece of Python code used in :py:func:`waflib.Tools.python.install_pyfile` for installing python files
+"""
+
+@extension('.py')
+def process_py(self, node):
+ """
+ Add a callback using :py:func:`waflib.Tools.python.install_pyfile` to install a python file
+ """
+ try:
+ if not self.bld.is_install:
+ return
+ except:
+ return
+
+ try:
+ if not self.install_path:
+ return
+ except AttributeError:
+ self.install_path = '${PYTHONDIR}'
+
+ # i wonder now why we wanted to do this after the build is over
+ # issue #901: people want to preserve the structure of installed files
+ def inst_py(ctx):
+ install_from = getattr(self, 'install_from', None)
+ if install_from:
+ install_from = self.path.find_dir(install_from)
+ install_pyfile(self, node, install_from)
+ self.bld.add_post_fun(inst_py)
+
+def install_pyfile(self, node, install_from=None):
+ """
+ Execute the installation of a python file
+
+ :param node: python file
+ :type node: :py:class:`waflib.Node.Node`
+ """
+
+ from_node = install_from or node.parent
+ tsk = self.bld.install_as(self.install_path + '/' + node.path_from(from_node), node, postpone=False)
+ path = tsk.get_install_path()
+
+ if self.bld.is_install < 0:
+ info("+ removing byte compiled python files")
+ for x in 'co':
+ try:
+ os.remove(path + x)
+ except OSError:
+ pass
+
+ if self.bld.is_install > 0:
+ try:
+ st1 = os.stat(path)
+ except:
+ error('The python file is missing, this should not happen')
+
+ for x in ['c', 'o']:
+ do_inst = self.env['PY' + x.upper()]
+ try:
+ st2 = os.stat(path + x)
+ except OSError:
+ pass
+ else:
+ if st1.st_mtime <= st2.st_mtime:
+ do_inst = False
+
+ if do_inst:
+ lst = (x == 'o') and [self.env['PYFLAGS_OPT']] or []
+ (a, b, c) = (path, path + x, tsk.get_install_path(destdir=False) + x)
+ argv = self.env['PYTHON'] + lst + ['-c', INST, a, b, c]
+ info('+ byte compiling %r' % (path + x))
+ ret = Utils.subprocess.Popen(argv).wait()
+ if ret:
+ raise Errors.WafError('py%s compilation failed %r' % (x, path))
+
+@feature('py')
+def feature_py(self):
+ """
+ Dummy feature which does nothing
+ """
+ pass
+
+@feature('pyext')
+@before_method('propagate_uselib_vars', 'apply_link')
+@after_method('apply_bundle')
+def init_pyext(self):
+ """
+ Change the values of *cshlib_PATTERN* and *cxxshlib_PATTERN* to remove the
+ *lib* prefix from library names.
+ """
+ try:
+ if not self.install_path:
+ return
+ except AttributeError:
+ self.install_path = '${PYTHONARCHDIR}'
+ self.uselib = self.to_list(getattr(self, 'uselib', []))
+ if not 'PYEXT' in self.uselib:
+ self.uselib.append('PYEXT')
+ # override shlib_PATTERN set by the osx module
+ self.env['cshlib_PATTERN'] = self.env['cxxshlib_PATTERN'] = self.env['macbundle_PATTERN'] = self.env['pyext_PATTERN']
+
+@feature('pyext')
+@before_method('apply_link', 'apply_bundle')
+def set_bundle(self):
+ if sys.platform.startswith('darwin'):
+ self.mac_bundle = True
+
+@before_method('propagate_uselib_vars')
+@feature('pyembed')
+def init_pyembed(self):
+ """
+ Add the PYEMBED variable.
+ """
+ self.uselib = self.to_list(getattr(self, 'uselib', []))
+ if not 'PYEMBED' in self.uselib:
+ self.uselib.append('PYEMBED')
+
+@conf
+def get_python_variables(conf, variables, imports=['import sys']):
+ """
+ Execute a python interpreter to dump configuration variables
+
+ :param variables: variables to print
+ :type variables: list of string
+ :param imports: one import by element
+ :type imports: list of string
+ :return: the variable values
+ :rtype: list of string
+ """
+ program = list(imports)
+ program.append('')
+ for v in variables:
+ program.append("print(repr(%s))" % v)
+ os_env = dict(os.environ)
+ try:
+ del os_env['MACOSX_DEPLOYMENT_TARGET'] # see comments in the OSX tool
+ except KeyError:
+ pass
+
+ try:
+ out = conf.cmd_and_log(conf.env.PYTHON + ['-c', '\n'.join(program)], env=os_env)
+ except Errors.WafError:
+ conf.fatal('The distutils module is unusable: install "python-devel"?')
+ return_values = []
+ for s in out.split('\n'):
+ s = s.strip()
+ if not s:
+ continue
+ if s == 'None':
+ return_values.append(None)
+ elif s[0] == "'" and s[-1] == "'":
+ return_values.append(s[1:-1])
+ elif s[0].isdigit():
+ return_values.append(int(s))
+ else: break
+ return return_values
+
+@conf
+def check_python_headers(conf):
+ """
+ Check for headers and libraries necessary to extend or embed python by using the module *distutils*.
+ On success the environment variables xxx_PYEXT and xxx_PYEMBED are added:
+
+ * PYEXT: for compiling python extensions
+ * PYEMBED: for embedding a python interpreter
+ """
+
+ # FIXME rewrite
+
+ if not conf.env['CC_NAME'] and not conf.env['CXX_NAME']:
+ conf.fatal('load a compiler first (gcc, g++, ..)')
+
+ if not conf.env['PYTHON_VERSION']:
+ conf.check_python_version()
+
+ env = conf.env
+ pybin = conf.env.PYTHON
+ if not pybin:
+ conf.fatal('could not find the python executable')
+
+ v = 'prefix SO LDFLAGS LIBDIR LIBPL INCLUDEPY Py_ENABLE_SHARED MACOSX_DEPLOYMENT_TARGET LDSHARED CFLAGS'.split()
+ try:
+ lst = conf.get_python_variables(["get_config_var('%s') or ''" % x for x in v],
+ ['from distutils.sysconfig import get_config_var'])
+ except RuntimeError:
+ conf.fatal("Python development headers not found (-v for details).")
+
+ vals = ['%s = %r' % (x, y) for (x, y) in zip(v, lst)]
+ conf.to_log("Configuration returned from %r:\n%r\n" % (pybin, '\n'.join(vals)))
+
+ dct = dict(zip(v, lst))
+ x = 'MACOSX_DEPLOYMENT_TARGET'
+ if dct[x]:
+ conf.env[x] = conf.environ[x] = dct[x]
+
+ env['pyext_PATTERN'] = '%s' + dct['SO'] # not a mistake
+
+ # Check for python libraries for embedding
+
+ all_flags = dct['LDFLAGS'] + ' ' + dct['CFLAGS']
+ conf.parse_flags(all_flags, 'PYEMBED')
+
+ all_flags = dct['LDFLAGS'] + ' ' + dct['LDSHARED'] + ' ' + dct['CFLAGS']
+ conf.parse_flags(all_flags, 'PYEXT')
+
+ result = None
+ #name = 'python' + env['PYTHON_VERSION']
+
+ # TODO simplify this
+ for name in ('python' + env['PYTHON_VERSION'], 'python' + env['PYTHON_VERSION'].replace('.', '')):
+
+ # LIBPATH_PYEMBED is already set; see if it works.
+ if not result and env['LIBPATH_PYEMBED']:
+ path = env['LIBPATH_PYEMBED']
+ conf.to_log("\n\n# Trying default LIBPATH_PYEMBED: %r\n" % path)
+ result = conf.check(lib=name, uselib='PYEMBED', libpath=path, mandatory=False, msg='Checking for library %s in LIBPATH_PYEMBED' % name)
+
+ if not result and dct['LIBDIR']:
+ path = [dct['LIBDIR']]
+ conf.to_log("\n\n# try again with -L$python_LIBDIR: %r\n" % path)
+ result = conf.check(lib=name, uselib='PYEMBED', libpath=path, mandatory=False, msg='Checking for library %s in LIBDIR' % name)
+
+ if not result and dct['LIBPL']:
+ path = [dct['LIBPL']]
+ conf.to_log("\n\n# try again with -L$python_LIBPL (some systems don't install the python library in $prefix/lib)\n")
+ result = conf.check(lib=name, uselib='PYEMBED', libpath=path, mandatory=False, msg='Checking for library %s in python_LIBPL' % name)
+
+ if not result:
+ path = [os.path.join(dct['prefix'], "libs")]
+ conf.to_log("\n\n# try again with -L$prefix/libs, and pythonXY name rather than pythonX.Y (win32)\n")
+ result = conf.check(lib=name, uselib='PYEMBED', libpath=path, mandatory=False, msg='Checking for library %s in $prefix/libs' % name)
+
+ if result:
+ break # do not forget to set LIBPATH_PYEMBED
+
+ if result:
+ env['LIBPATH_PYEMBED'] = path
+ env.append_value('LIB_PYEMBED', [name])
+ else:
+ conf.to_log("\n\n### LIB NOT FOUND\n")
+
+ # under certain conditions, python extensions must link to
+ # python libraries, not just python embedding programs.
+ if (Utils.is_win32 or sys.platform.startswith('os2')
+ or dct['Py_ENABLE_SHARED']):
+ env['LIBPATH_PYEXT'] = env['LIBPATH_PYEMBED']
+ env['LIB_PYEXT'] = env['LIB_PYEMBED']
+
+ # We check that pythonX.Y-config exists, and if it exists we
+ # use it to get only the includes, else fall back to distutils.
+ num = '.'.join(env['PYTHON_VERSION'].split('.')[:2])
+ conf.find_program(['python%s-config' % num, 'python-config-%s' % num, 'python%sm-config' % num], var='PYTHON_CONFIG', mandatory=False)
+
+ includes = []
+ if conf.env.PYTHON_CONFIG:
+ for incstr in conf.cmd_and_log([ conf.env.PYTHON_CONFIG, '--includes']).strip().split():
+ # strip the -I or /I
+ if (incstr.startswith('-I') or incstr.startswith('/I')):
+ incstr = incstr[2:]
+ # append include path, unless already given
+ if incstr not in includes:
+ includes.append(incstr)
+ conf.to_log("Include path for Python extensions "
+ "(found via python-config --includes): %r\n" % (includes,))
+ env['INCLUDES_PYEXT'] = includes
+ env['INCLUDES_PYEMBED'] = includes
+ else:
+ conf.to_log("Include path for Python extensions "
+ "(found via distutils module): %r\n" % (dct['INCLUDEPY'],))
+ env['INCLUDES_PYEXT'] = [dct['INCLUDEPY']]
+ env['INCLUDES_PYEMBED'] = [dct['INCLUDEPY']]
+
+ # Code using the Python API needs to be compiled with -fno-strict-aliasing
+ if env['CC_NAME'] == 'gcc':
+ env.append_value('CFLAGS_PYEMBED', ['-fno-strict-aliasing'])
+ env.append_value('CFLAGS_PYEXT', ['-fno-strict-aliasing'])
+ if env['CXX_NAME'] == 'gcc':
+ env.append_value('CXXFLAGS_PYEMBED', ['-fno-strict-aliasing'])
+ env.append_value('CXXFLAGS_PYEXT', ['-fno-strict-aliasing'])
+
+ if env.CC_NAME == "msvc":
+ from distutils.msvccompiler import MSVCCompiler
+ dist_compiler = MSVCCompiler()
+ dist_compiler.initialize()
+ env.append_value('CFLAGS_PYEXT', dist_compiler.compile_options)
+ env.append_value('CXXFLAGS_PYEXT', dist_compiler.compile_options)
+ env.append_value('LINKFLAGS_PYEXT', dist_compiler.ldflags_shared)
+
+ # See if it compiles
+ try:
+ conf.check(header_name='Python.h', define_name='HAVE_PYTHON_H',
+ uselib='PYEMBED', fragment=FRAG,
+ errmsg='Could not find the python development headers')
+ except conf.errors.ConfigurationError:
+ # python3.2, oh yeah
+ conf.check_cfg(path=conf.env.PYTHON_CONFIG, package='', uselib_store='PYEMBED', args=['--cflags', '--libs'])
+ conf.check(header_name='Python.h', define_name='HAVE_PYTHON_H', msg='Getting the python flags from python-config',
+ uselib='PYEMBED', fragment=FRAG,
+ errmsg='Could not find the python development headers elsewhere')
+
+@conf
+def check_python_version(conf, minver=None):
+ """
+ Check if the python interpreter is found matching a given minimum version.
+ minver should be a tuple, eg. to check for python >= 2.4.2 pass (2,4,2) as minver.
+
+ If successful, PYTHON_VERSION is defined as 'MAJOR.MINOR'
+ (eg. '2.4') of the actual python version found, and PYTHONDIR is
+ defined, pointing to the site-packages directory appropriate for
+ this python version, where modules/packages/extensions should be
+ installed.
+
+ :param minver: minimum version
+ :type minver: tuple of int
+ """
+ assert minver is None or isinstance(minver, tuple)
+ pybin = conf.env['PYTHON']
+ if not pybin:
+ conf.fatal('could not find the python executable')
+
+ # Get python version string
+ cmd = pybin + ['-c', 'import sys\nfor x in sys.version_info: print(str(x))']
+ debug('python: Running python command %r' % cmd)
+ lines = conf.cmd_and_log(cmd).split()
+ assert len(lines) == 5, "found %i lines, expected 5: %r" % (len(lines), lines)
+ pyver_tuple = (int(lines[0]), int(lines[1]), int(lines[2]), lines[3], int(lines[4]))
+
+ # compare python version with the minimum required
+ result = (minver is None) or (pyver_tuple >= minver)
+
+ if result:
+ # define useful environment variables
+ pyver = '.'.join([str(x) for x in pyver_tuple[:2]])
+ conf.env['PYTHON_VERSION'] = pyver
+
+ if 'PYTHONDIR' in conf.environ:
+ pydir = conf.environ['PYTHONDIR']
+ else:
+ if Utils.is_win32:
+ (python_LIBDEST, pydir) = \
+ conf.get_python_variables(
+ ["get_config_var('LIBDEST') or ''",
+ "get_python_lib(standard_lib=0, prefix=%r) or ''" % conf.env['PREFIX']],
+ ['from distutils.sysconfig import get_config_var, get_python_lib'])
+ else:
+ python_LIBDEST = None
+ (pydir,) = \
+ conf.get_python_variables(
+ ["get_python_lib(standard_lib=0, prefix=%r) or ''" % conf.env['PREFIX']],
+ ['from distutils.sysconfig import get_python_lib'])
+ if python_LIBDEST is None:
+ if conf.env['LIBDIR']:
+ python_LIBDEST = os.path.join(conf.env['LIBDIR'], "python" + pyver)
+ else:
+ python_LIBDEST = os.path.join(conf.env['PREFIX'], "lib", "python" + pyver)
+
+
+ if 'PYTHONARCHDIR' in conf.environ:
+ pyarchdir = conf.environ['PYTHONARCHDIR']
+ else:
+ (pyarchdir, ) = conf.get_python_variables(
+ ["get_python_lib(plat_specific=1, standard_lib=0, prefix=%r) or ''" % conf.env['PREFIX']],
+ ['from distutils.sysconfig import get_python_lib'])
+ if not pyarchdir:
+ pyarchdir = pydir
+
+ if hasattr(conf, 'define'): # conf.define is added by the C tool, so may not exist
+ conf.define('PYTHONDIR', pydir)
+ conf.define('PYTHONARCHDIR', pyarchdir)
+
+ conf.env['PYTHONDIR'] = pydir
+ conf.env['PYTHONARCHDIR'] = pyarchdir
+
+ # Feedback
+ pyver_full = '.'.join(map(str, pyver_tuple[:3]))
+ if minver is None:
+ conf.msg('Checking for python version', pyver_full)
+ else:
+ minver_str = '.'.join(map(str, minver))
+ conf.msg('Checking for python version', pyver_tuple, ">= %s" % (minver_str,) and 'GREEN' or 'YELLOW')
+
+ if not result:
+ conf.fatal('The python version is too old, expecting %r' % (minver,))
+
+PYTHON_MODULE_TEMPLATE = '''
+import %s
+print(1)
+'''
+
+@conf
+def check_python_module(conf, module_name):
+ """
+ Check if the selected python interpreter can import the given python module::
+
+ def configure(conf):
+ conf.check_python_module('pygccxml')
+
+ :param module_name: module
+ :type module_name: string
+ """
+ conf.start_msg('Python module %s' % module_name)
+ try:
+ conf.cmd_and_log(conf.env['PYTHON'] + ['-c', PYTHON_MODULE_TEMPLATE % module_name])
+ except:
+ conf.end_msg(False)
+ conf.fatal('Could not find the python module %r' % module_name)
+ conf.end_msg(True)
+
+def configure(conf):
+ """
+ Detect the python interpreter
+ """
+ try:
+ conf.find_program('python', var='PYTHON')
+ except conf.errors.ConfigurationError:
+ warn("could not find a python executable, setting to sys.executable '%s'" % sys.executable)
+ conf.env.PYTHON = sys.executable
+
+ if conf.env.PYTHON != sys.executable:
+ warn("python executable '%s' different from sys.executable '%s'" % (conf.env.PYTHON, sys.executable))
+ conf.env.PYTHON = conf.cmd_to_list(conf.env.PYTHON)
+
+ v = conf.env
+ v['PYCMD'] = '"import sys, py_compile;py_compile.compile(sys.argv[1], sys.argv[2])"'
+ v['PYFLAGS'] = ''
+ v['PYFLAGS_OPT'] = '-O'
+
+ v['PYC'] = getattr(Options.options, 'pyc', 1)
+ v['PYO'] = getattr(Options.options, 'pyo', 1)
+
+def options(opt):
+ """
+ Add the options ``--nopyc`` and ``--nopyo``
+ """
+ opt.add_option('--nopyc',
+ action='store_false',
+ default=1,
+ help = 'Do not install bytecode compiled .pyc files (configuration) [Default:install]',
+ dest = 'pyc')
+ opt.add_option('--nopyo',
+ action='store_false',
+ default=1,
+ help='Do not install optimised compiled .pyo files (configuration) [Default:install]',
+ dest='pyo')
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/waf-tools/relocation.py Mon Oct 17 16:59:17 2011 -0400
@@ -0,0 +1,85 @@
+#! /usr/bin/env python
+# encoding: utf-8
+
+"""
+Waf 1.6
+
+Try to detect if the project directory was relocated, and if it was,
+change the node representing the project directory. Just call:
+
+ waf configure build
+
+Note that if the project directory name changes, the signatures for the tasks using
+files in that directory will change, causing a partial build.
+"""
+
+import os
+from waflib import Build, ConfigSet, Task, Utils, Errors
+from waflib.TaskGen import feature, before_method, after_method
+
+EXTRA_LOCK = '.old_srcdir'
+
+old1 = Build.BuildContext.store
+def store(self):
+ old1(self)
+ db = os.path.join(self.variant_dir, EXTRA_LOCK)
+ env = ConfigSet.ConfigSet()
+ env.SRCDIR = self.srcnode.abspath()
+ env.store(db)
+Build.BuildContext.store = store
+
+old2 = Build.BuildContext.init_dirs
+def init_dirs(self):
+
+ if not (os.path.isabs(self.top_dir) and os.path.isabs(self.out_dir)):
+ raise Errors.WafError('The project was not configured: run "waf configure" first!')
+
+ srcdir = None
+ db = os.path.join(self.variant_dir, EXTRA_LOCK)
+ env = ConfigSet.ConfigSet()
+ try:
+ env.load(db)
+ srcdir = env.SRCDIR
+ except:
+ pass
+
+ if srcdir:
+ d = self.root.find_node(srcdir)
+ if d and srcdir != self.top_dir and getattr(d, 'children', ''):
+ srcnode = self.root.make_node(self.top_dir)
+ print("relocating the source directory %r -> %r" % (srcdir, self.top_dir))
+ srcnode.children = {}
+
+ for (k, v) in d.children.items():
+ srcnode.children[k] = v
+ v.parent = srcnode
+ d.children = {}
+
+ old2(self)
+
+Build.BuildContext.init_dirs = init_dirs
+
+
+def uid(self):
+ try:
+ return self.uid_
+ except AttributeError:
+ # this is not a real hot zone, but we want to avoid surprizes here
+ m = Utils.md5()
+ up = m.update
+ up(self.__class__.__name__.encode())
+ for x in self.inputs + self.outputs:
+ up(x.path_from(x.ctx.srcnode).encode())
+ self.uid_ = m.digest()
+ return self.uid_
+Task.Task.uid = uid
+
+@feature('c', 'cxx', 'd', 'go', 'asm', 'fc', 'includes')
+@after_method('propagate_uselib_vars', 'process_source')
+def apply_incpaths(self):
+ lst = self.to_incnodes(self.to_list(getattr(self, 'includes', [])) + self.env['INCLUDES'])
+ self.includes_nodes = lst
+ bld = self.bld
+ self.env['INCPATHS'] = [x.is_child_of(bld.srcnode) and x.path_from(bld.srcnode) or x.abspath() for x in lst]
+
+
--- a/wscript Sat Aug 20 14:41:19 2011 -0400
+++ b/wscript Mon Oct 17 16:59:17 2011 -0400
@@ -11,24 +11,21 @@
import textwrap
# WAF modules
-import pproc as subprocess
+import subprocess
import Options
import Logs
import TaskGen
-import Constants
-
-import ccroot
-ccroot.USE_TOP_LEVEL = True
import Task
-Task.algotype = Constants.JOBCONTROL # so that Task.maxjobs=1 takes effect
import Utils
import Build
import Configure
import Scripting
+from waflib.Errors import WafError
+
from utils import read_config_file
# By default, all modules will be enabled, examples will be disabled,
@@ -58,7 +55,11 @@
# local modules
import wutils
-Configure.autoconfig = 1
+Configure.autoconfig = 0
+
+# until http://code.google.com/p/waf/issues/detail?id=1039 gets fixed...
+wutils.monkey_patch_Runner_start()
+
# the following two variables are used by the target "waf dist"
VERSION = file("VERSION", "rt").read().strip()
@@ -67,14 +68,14 @@
wutils.VERSION = VERSION
wutils.APPNAME = APPNAME
-if re.match(r"\d+\.\d+(\.\d+)?", VERSION) is not None:
+# note: here we disable the VNUM for OSX since it causes problems (bug #1251)
+wutils.VNUM = None
+if sys.platform != 'darwin' and re.match(r"^\d+\.\d+(\.\d+)?$", VERSION) is not None:
wutils.VNUM = VERSION
-else:
- wutils.VNUM = None
# these variables are mandatory ('/' are converted automatically)
-srcdir = '.'
-blddir = 'build'
+top = '.'
+out = 'build'
def load_env():
bld_cls = getattr(Utils.g_module, 'build_context', Utils.Context)
@@ -124,12 +125,12 @@
if i != 1:
print
-def set_options(opt):
+def options(opt):
# options provided by the modules
- opt.tool_options('compiler_cc')
- opt.tool_options('compiler_cxx')
- opt.tool_options('cflags')
- opt.tool_options('gnu_dirs')
+ opt.load('compiler_c')
+ opt.load('compiler_cxx')
+ opt.load('cflags')
+ opt.load('gnu_dirs')
opt.add_option('--cwd',
help=('Set the working directory for a program.'),
@@ -208,10 +209,6 @@
help=('Compile NS-3 statically: works only on linux, without python'),
dest='enable_static', action='store_true',
default=False)
- opt.add_option('--enable-shared-and-static',
- help=('Compile NS-3 both shared and static libraries at the same time: static works only on linux'),
- dest='enable_shared_and_static', action='store_true',
- default=False)
opt.add_option('--enable-mpi',
help=('Compile NS-3 with MPI and distributed simulation support'),
dest='enable_mpi', action='store_true',
@@ -228,42 +225,77 @@
opt.sub_options('src/internet')
-def _check_compilation_flag(conf, flag, mode='cxx'):
+def _check_compilation_flag(conf, flag, mode='cxx', linkflags=None):
"""
Checks if the C++ compiler accepts a certain compilation flag or flags
flag: can be a string or a list of strings
"""
+ l = []
+ if flag:
+ l.append(flag)
+ if isinstance(linkflags, list):
+ l.extend(linkflags)
+ else:
+ if linkflags:
+ l.append(linkflags)
+ if len(l) > 1:
+ flag_str = 'flags ' + ' '.join(l)
+ else:
+ flag_str = 'flag ' + ' '.join(l)
+ if flag_str > 28:
+ flag_str = flag_str[:28] + "..."
+ conf.start_msg('Checking for compilation %s support' % (flag_str,))
env = conf.env.copy()
+
+ if mode == 'cc':
+ mode = 'c'
+
if mode == 'cxx':
fname = 'test.cc'
env.append_value('CXXFLAGS', flag)
else:
fname = 'test.c'
- env.append_value('CCFLAGS', flag)
+ env.append_value('CFLAGS', flag)
+
+ if linkflags is not None:
+ env.append_value("LINKFLAGS", linkflags)
+
try:
retval = conf.run_c_code(code='#include <stdio.h>\nint main() { return 0; }\n',
env=env, compile_filename=fname,
- compile_mode=mode, type='cprogram', execute=False)
+ features=[mode, mode+'program'], execute=False)
except Configure.ConfigurationError:
ok = False
else:
ok = (retval == 0)
- conf.check_message_custom(flag, 'support', (ok and 'yes' or 'no'))
+ conf.end_msg(ok)
return ok
def report_optional_feature(conf, name, caption, was_enabled, reason_not_enabled):
- conf.env.append_value('NS3_OPTIONAL_FEATURES', (name, caption, was_enabled, reason_not_enabled))
+ conf.env.append_value('NS3_OPTIONAL_FEATURES', [(name, caption, was_enabled, reason_not_enabled)])
+
+
+# starting with waf 1.6, conf.check() becomes fatal by default if the
+# test fails, this alternative method makes the test non-fatal, as it
+# was in waf <= 1.5
+def _check_nonfatal(conf, *args, **kwargs):
+ try:
+ return conf.check(*args, **kwargs)
+ except conf.errors.ConfigurationError:
+ return None
def configure(conf):
+ conf.check_tool("relocation", ["waf-tools"])
+
# attach some extra methods
+ conf.check_nonfatal = types.MethodType(_check_nonfatal, conf)
conf.check_compilation_flag = types.MethodType(_check_compilation_flag, conf)
conf.report_optional_feature = types.MethodType(report_optional_feature, conf)
conf.env['NS3_OPTIONAL_FEATURES'] = []
- conf.env['NS3_BUILDDIR'] = conf.blddir
- conf.check_tool('compiler_cc')
+ conf.check_tool('compiler_c')
conf.check_tool('compiler_cxx')
conf.check_tool('cflags', ['waf-tools'])
try:
@@ -273,31 +305,19 @@
conf.check_tool('command', ['waf-tools'])
conf.check_tool('gnu_dirs')
- #if os.path.exists('/usr/lib64'):
- # conf.env.LIBDIR = os.path.join(conf.env.PREFIX, "lib64")
-
- # create the second environment, set the variant and set its name
- variant_env = conf.env.copy()
- variant_name = Options.options.build_profile
+ env = conf.env
if Options.options.enable_gcov:
- variant_name += '-gcov'
- variant_env.append_value('CCFLAGS', '-fprofile-arcs')
- variant_env.append_value('CCFLAGS', '-ftest-coverage')
- variant_env.append_value('CXXFLAGS', '-fprofile-arcs')
- variant_env.append_value('CXXFLAGS', '-ftest-coverage')
- variant_env.append_value('LINKFLAGS', '-fprofile-arcs')
-
- conf.env['NS3_ACTIVE_VARIANT'] = variant_name
- variant_env['NS3_ACTIVE_VARIANT'] = variant_name
- variant_env.set_variant(variant_name)
- conf.set_env_name(variant_name, variant_env)
- conf.setenv(variant_name)
- env = variant_env
+ env['GCOV_ENABLED'] = True
+ env.append_value('CCFLAGS', '-fprofile-arcs')
+ env.append_value('CCFLAGS', '-ftest-coverage')
+ env.append_value('CXXFLAGS', '-fprofile-arcs')
+ env.append_value('CXXFLAGS', '-ftest-coverage')
+ env.append_value('LINKFLAGS', '-lgcov')
if Options.options.build_profile == 'debug':
- env.append_value('CXXDEFINES', 'NS3_ASSERT_ENABLE')
- env.append_value('CXXDEFINES', 'NS3_LOG_ENABLE')
+ env.append_value('DEFINES', 'NS3_ASSERT_ENABLE')
+ env.append_value('DEFINES', 'NS3_LOG_ENABLE')
env['PLATFORM'] = sys.platform
@@ -325,43 +345,21 @@
env['WL_SONAME_SUPPORTED'] = True
env['ENABLE_STATIC_NS3'] = False
- if Options.options.enable_static or Options.options.enable_shared_and_static:
- if env['PLATFORM'].startswith('linux') and \
- env['CXX_NAME'] in ['gcc', 'icc']:
- if re.match('i[3-6]86', os.uname()[4]):
+ if Options.options.enable_static:
+ if Options.platform == 'darwin':
+ if conf.check_compilation_flag(flag=[], linkflags=['-Wl,-all_load']):
conf.report_optional_feature("static", "Static build", True, '')
- if Options.options.enable_static:
- env['ENABLE_STATIC_NS3'] = True
- if Options.options.enable_shared_and_static:
- env['ENABLE_SHARED_AND_STATIC_NS3'] = True
- elif os.uname()[4] == 'x86_64':
- if env['ENABLE_PYTHON_BINDINGS'] and \
- not conf.check_compilation_flag('-mcmodel=large'):
- conf.report_optional_feature("static", "Static build", False,
- "Can't enable static builds because " + \
- "no -mcmodel=large compiler " \
- "option. Try --disable-python or upgrade your " \
- "compiler to at least gcc 4.3.x.")
- else:
- conf.report_optional_feature("static", "Static build", True, '')
- if Options.options.enable_static:
- env['ENABLE_STATIC_NS3'] = True
- if Options.options.enable_shared_and_static:
- env['ENABLE_SHARED_AND_STATIC_NS3'] = True
- elif env['CXX_NAME'] == 'gcc' and \
- (env['PLATFORM'].startswith('darwin') or \
- env['PLATFORM'].startswith('cygwin')):
+ env['ENABLE_STATIC_NS3'] = True
+ else:
+ conf.report_optional_feature("static", "Static build", False,
+ "Link flag -Wl,-all_load does not work")
+ else:
+ if conf.check_compilation_flag(flag=[], linkflags=['-Wl,--whole-archive,-Bstatic', '-Wl,-Bdynamic,--no-whole-archive']):
conf.report_optional_feature("static", "Static build", True, '')
- if Options.options.enable_static:
- env['ENABLE_STATIC_NS3'] = True
- if Options.options.enable_shared_and_static:
- env['ENABLE_SHARED_AND_STATIC_NS3'] = True
- else:
- conf.report_optional_feature("static", "Static build", False,
- "Unsupported platform")
- else:
- conf.report_optional_feature("static", "Static build", False,
- "option --enable-static not selected")
+ env['ENABLE_STATIC_NS3'] = True
+ else:
+ conf.report_optional_feature("static", "Static build", False,
+ "Link flag -Wl,--whole-archive,-Bstatic does not work")
conf.env['MODULES_NOT_BUILT'] = []
@@ -395,14 +393,17 @@
if not_built_name in conf.env['NS3_ENABLED_MODULES']:
conf.env['NS3_ENABLED_MODULES'].remove(not_built_name)
if not conf.env['NS3_ENABLED_MODULES']:
- raise Utils.WafError('Exiting because the ' + not_built + ' module can not be built and it was the only one enabled.')
+ raise WafError('Exiting because the ' + not_built + ' module can not be built and it was the only one enabled.')
conf.sub_config('bindings/python')
conf.sub_config('src/mpi')
# for suid bits
- conf.find_program('sudo', var='SUDO')
+ try:
+ conf.find_program('sudo', var='SUDO')
+ except WafError:
+ pass
why_not_sudo = "because we like it"
if Options.options.enable_sudo and conf.env['SUDO']:
@@ -466,7 +467,10 @@
conf.report_optional_feature("ENABLE_EXAMPLES", "Build examples", env['ENABLE_EXAMPLES'],
why_not_examples)
- conf.find_program('valgrind', var='VALGRIND')
+ try:
+ conf.find_program('valgrind', var='VALGRIND')
+ except WafError:
+ pass
# These flags are used for the implicitly dependent modules.
if env['ENABLE_STATIC_NS3']:
@@ -483,12 +487,10 @@
conf.env['ENABLE_GSL'],
"GSL not found")
if have_gsl:
- conf.env.append_value('CXXDEFINES', "ENABLE_GSL")
- conf.env.append_value('CCDEFINES', "ENABLE_GSL")
+ conf.env.append_value('DEFINES', "ENABLE_GSL")
# for compiling C code, copy over the CXX* flags
conf.env.append_value('CCFLAGS', conf.env['CXXFLAGS'])
- conf.env.append_value('CCDEFINES', conf.env['CXXDEFINES'])
def add_gcc_flag(flag):
if env['COMPILER_CXX'] == 'g++' and 'CXXFLAGS' not in os.environ:
@@ -502,7 +504,10 @@
add_gcc_flag('-fstrict-aliasing')
add_gcc_flag('-Wstrict-aliasing')
- conf.find_program('doxygen', var='DOXYGEN')
+ try:
+ conf.find_program('doxygen', var='DOXYGEN')
+ except WafError:
+ pass
# append user defined flags after all our ones
for (confvar, envvar) in [['CCFLAGS', 'CCFLAGS_EXTRA'],
@@ -522,23 +527,20 @@
status = 'not enabled (%s)' % reason_not_enabled
print "%-30s: %s" % (caption, status)
-class SuidBuildTask(Task.TaskBase):
+
+class SuidBuild_task(Task.TaskBase):
"""task that makes a binary Suid
"""
- after = 'cxx_link cc_link'
- maxjobs = 1
- def __init__(self, bld, program):
- self.bld = bld
+ after = 'link'
+ def __init__(self, *args, **kwargs):
+ super(SuidBuild_task, self).__init__(*args, **kwargs)
self.m_display = 'build-suid'
- self.__program = program
- self.__env = bld.env.copy ()
- super(SuidBuildTask, self).__init__(generator=self)
try:
- program_obj = wutils.find_program(self.__program.target, self.__env)
+ program_obj = wutils.find_program(self.generator.target, self.generator.env)
except ValueError, ex:
- raise Utils.WafError(str(ex))
- program_node = program_obj.path.find_or_declare(ccroot.get_target_name(program_obj))
- self.filename = program_node.abspath(self.__env)
+ raise WafError(str(ex))
+ program_node = program_obj.path.find_or_declare(program_obj.target)
+ self.filename = program_node.abspath()
def run(self):
@@ -553,38 +555,49 @@
"RUN_ME SKIP_ME or ASK_LATER"
st = os.stat(self.filename)
if st.st_uid == 0:
- return Constants.SKIP_ME
+ return Task.SKIP_ME
else:
- return Constants.RUN_ME
-
+ return Task.RUN_ME
def create_suid_program(bld, name):
- program = bld.new_task_gen('cxx', 'program')
+ grp = bld.current_group
+ bld.add_group() # this to make sure no two sudo tasks run at the same time
+ program = bld.new_task_gen(features=['cxx', 'cxxprogram'])
program.is_ns3_program = True
program.module_deps = list()
program.name = name
program.target = name
if bld.env['ENABLE_SUDO']:
- SuidBuildTask(bld, program)
+ program.create_task("SuidBuild")
+
+ bld.set_group(grp)
return program
def create_ns3_program(bld, name, dependencies=('core',)):
- program = bld.new_task_gen('cxx', 'program')
+ program = bld.new_task_gen(features=['cxx', 'cxxprogram'])
program.is_ns3_program = True
program.name = name
program.target = program.name
# Each of the modules this program depends on has its own library.
program.ns3_module_dependencies = ['ns3-'+dep for dep in dependencies]
+ program.includes = "# #/.."
+ program.use = program.ns3_module_dependencies
+ if program.env['ENABLE_STATIC_NS3']:
+ if sys.platform == 'darwin':
+ program.env.STLIB_MARKER = '-Wl,-all_load'
+ else:
+ program.env.STLIB_MARKER = '-Wl,--whole-archive,-Bstatic'
+ program.env.SHLIB_MARKER = '-Wl,-Bdynamic,--no-whole-archive'
return program
def register_ns3_script(bld, name, dependencies=('core',)):
ns3_module_dependencies = ['ns3-'+dep for dep in dependencies]
- bld.env.append_value('NS3_SCRIPT_DEPENDENCIES', (name, ns3_module_dependencies))
+ bld.env.append_value('NS3_SCRIPT_DEPENDENCIES', [(name, ns3_module_dependencies)])
def add_examples_programs(bld):
- env = bld.env_of_name('default')
+ env = bld.env
if env['ENABLE_EXAMPLES']:
for dir in os.listdir('examples'):
if dir.startswith('.') or dir == 'CVS':
@@ -613,23 +626,30 @@
obj.name = obj.target
-def _add_ns3_program_missing_deps(bld, program):
- deps_found = program.ns3_module_dependencies
- program.uselib_local = getattr(program, "uselib_local", []) + [dep + "--lib" for dep in deps_found]
- if program.env['ENABLE_STATIC_NS3'] and not program.env['ENABLE_SHARED_AND_STATIC_NS3']:
- if sys.platform == 'darwin':
- program.env.append_value('LINKFLAGS', '-Wl,-all_load')
- for dep in deps_found:
- program.env.append_value('LINKFLAGS', '-l' + dep)
+def _get_all_task_gen(self):
+ for group in self.groups:
+ for taskgen in group:
+ yield taskgen
+
+
+# ok, so WAF does not provide an API to prevent an
+# arbitrary taskgen from running; we have to muck around with
+# WAF internal state, something that might stop working if
+# WAF is upgraded...
+def _exclude_taskgen(self, taskgen):
+ for group in self.groups:
+ for tg1 in group:
+ if tg1 is taskgen:
+ group.remove(tg1)
+ break
else:
- program.env.append_value('LINKFLAGS', '-Wl,--whole-archive,-Bstatic')
- for dep in deps_found:
- program.env.append_value('LINKFLAGS', '-l' + dep)
- program.env.append_value('LINKFLAGS', '-Wl,-Bdynamic,--no-whole-archive')
-
+ continue
+ break
def build(bld):
+ env = bld.env
+
# If --enabled-modules option was given, then print a warning
# message and exit this function.
if Options.options.enable_modules:
@@ -653,17 +673,12 @@
bld.create_ns3_program = types.MethodType(create_ns3_program, bld)
bld.register_ns3_script = types.MethodType(register_ns3_script, bld)
bld.create_suid_program = types.MethodType(create_suid_program, bld)
-
- # switch default variant to the one matching our debug level
- variant_name = bld.env_of_name('default')['NS3_ACTIVE_VARIANT']
- variant_env = bld.env_of_name(variant_name)
- bld.all_envs['default'] = variant_env
+ bld.__class__.all_task_gen = property(_get_all_task_gen)
+ bld.exclude_taskgen = types.MethodType(_exclude_taskgen, bld)
# process subfolders from here
bld.add_subdirs('src')
- env = bld.env
-
# If modules have been enabled, then set lists of enabled modules
# and enabled module test libraries.
if env['NS3_ENABLED_MODULES']:
@@ -675,11 +690,11 @@
while changed:
changed = False
for module in modules:
- module_obj = bld.name_to_obj(module, env)
+ module_obj = bld.get_tgen_by_name(module)
if module_obj is None:
raise ValueError("module %s not found" % module)
# Each enabled module has its own library.
- for dep in module_obj.uselib_local:
+ for dep in module_obj.use:
if not dep.startswith('ns3-'):
continue
if dep not in modules:
@@ -701,25 +716,11 @@
if env['NS3_ENABLED_MODULES']:
modules = env['NS3_ENABLED_MODULES']
- def exclude_taskgen(bld, taskgen):
- # ok, so WAF does not provide an API to prevent an
- # arbitrary taskgen from running; we have to muck around with
- # WAF internal state, something that might stop working if
- # WAF is upgraded...
- bld.all_task_gen.remove(taskgen)
- for group in bld.task_manager.groups:
- try:
- group.tasks_gen.remove(taskgen)
- except ValueError:
- pass
- else:
- break
-
# Exclude the programs other misc task gens that depend on disabled modules
for obj in list(bld.all_task_gen):
# check for ns3moduleheader_taskgen
- if type(obj).__name__ == 'ns3moduleheader_taskgen':
+ if 'ns3moduleheader' in getattr(obj, "features", []):
if ("ns3-%s" % obj.module) not in modules:
obj.mode = 'remove' # tell it to remove headers instead of installing
@@ -729,7 +730,7 @@
program_built = True
for dep in obj.ns3_module_dependencies:
if dep not in modules: # prog. depends on a module that isn't enabled?
- exclude_taskgen(bld, obj)
+ bld.exclude_taskgen(obj)
program_built = False
break
@@ -740,15 +741,15 @@
# disable the modules themselves
if hasattr(obj, "is_ns3_module") and obj.name not in modules:
- exclude_taskgen(bld, obj) # kill the module
+ bld.exclude_taskgen(obj) # kill the module
# disable the module test libraries
if hasattr(obj, "is_ns3_module_test_library"):
if not env['ENABLE_TESTS'] or (obj.module_name not in modules):
- exclude_taskgen(bld, obj) # kill the module test library
+ bld.exclude_taskgen(obj) # kill the module test library
# disable the ns3header_taskgen
- if type(obj).__name__ == 'ns3header_taskgen':
+ if 'ns3header' in getattr(obj, "features", []):
if ("ns3-%s" % obj.module) not in modules:
obj.mode = 'remove' # tell it to remove headers instead of installing
@@ -770,35 +771,10 @@
bld.add_subdirs('bindings/python')
- ## do a topological sort on the modules graph
- dep_graph = []
- for gen in bld.all_task_gen:
- if type(gen).__name__ in ['ns3module_taskgen']:
- for dep in gen.dependencies:
- dep_graph.append(("ns3-"+dep, gen.name))
- dep_graph.sort()
- sys.path.insert(0, "bindings/python")
- from topsort import topsort
- sorted_ns3_modules = topsort(dep_graph)
- #print sorted_ns3_modules
-
- # we need to post() the ns3 modules, so they create libraries underneath, and programs can list them in uselib_local
- for module in sorted_ns3_modules:
- gen = bld.name_to_obj(module, bld.env)
- if type(gen).__name__ in ['ns3module_taskgen']:
- gen.post()
- for lib in gen.libs:
- lib.post()
-
# Process this subfolder here after the lists of enabled modules
# and module test libraries have been set.
bld.add_subdirs('utils')
- for gen in bld.all_task_gen:
- if not getattr(gen, "is_ns3_program", False) or not hasattr(gen, "ns3_module_dependencies"):
- continue
- _add_ns3_program_missing_deps(bld, gen)
-
if Options.options.run:
# Check that the requested program name is valid
program_name, dummy_program_argv = wutils.get_run_program(Options.options.run, wutils.get_command_template(env))
@@ -806,7 +782,7 @@
# When --run'ing a program, tell WAF to only build that program,
# nothing more; this greatly speeds up compilation when all you
# want to do is run a test program.
- Options.options.compile_targets += ',' + os.path.basename(program_name)
+ Options.options.targets += ',' + os.path.basename(program_name)
for gen in bld.all_task_gen:
if type(gen).__name__ in ['ns3header_taskgen', 'ns3moduleheader_taskgen']:
gen.post()
@@ -815,6 +791,8 @@
_doxygen(bld)
raise SystemExit(0)
+
+
def shutdown(ctx):
bld = wutils.bld
if wutils.bld is None:
@@ -826,9 +804,9 @@
# clean.
if ((not Options.options.run)
and (not Options.options.pyrun)
- and ('clean' not in Options.arg_line)
- and ('distclean' not in Options.arg_line)
- and ('shell' not in Options.arg_line)):
+ and ('clean' not in Options.commands)
+ and ('distclean' not in Options.commands)
+ and ('shell' not in Options.commands)):
# Print the list of built modules.
print
@@ -844,7 +822,7 @@
print
# Write the build status file.
- build_status_file = os.path.join (env['NS3_BUILDDIR'], env['NS3_ACTIVE_VARIANT'], 'build-status.py')
+ build_status_file = os.path.join(bld.out_dir, 'build-status.py')
out = open(build_status_file, 'w')
out.write('#! /usr/bin/env python\n')
out.write('\n')
@@ -857,7 +835,7 @@
out.close()
if Options.options.lcov_report:
- lcov_report()
+ lcov_report(bld)
if Options.options.run:
wutils.run_program(Options.options.run, env, wutils.get_command_template(env),
@@ -870,22 +848,34 @@
raise SystemExit(0)
if Options.options.shell:
- raise Utils.WafError("Please run `./waf shell' now, instead of `./waf --shell'")
+ raise WafError("Please run `./waf shell' now, instead of `./waf --shell'")
if Options.options.check:
- raise Utils.WafError("Please run `./test.py' now, instead of `./waf --check'")
+ raise WafError("Please run `./test.py' now, instead of `./waf --check'")
check_shell(bld)
-check_context = Build.BuildContext
+
+
+from waflib import Context, Build
+class CheckContext(Context.Context):
+ """run the equivalent of the old ns-3 unit tests using test.py"""
+ cmd = 'check'
+
+ def execute(self):
-def check(bld):
- """run the equivalent of the old ns-3 unit tests using test.py"""
- env = wutils.bld.env
- wutils.run_python_program("test.py -n -c core", env)
+ # first we execute the build
+ bld = Context.create_context("build")
+ bld.options = Options.options # provided for convenience
+ bld.cmd = "build"
+ bld.execute()
+
+ wutils.bld = bld
+ wutils.run_python_program("test.py -n -c core", bld.env)
+
class print_introspected_doxygen_task(Task.TaskBase):
- after = 'cc cxx cc_link cxx_link'
+ after = 'cc cxx link'
color = 'BLUE'
def __init__(self, bld):
@@ -910,13 +900,21 @@
pass
else:
prog = program_obj.path.find_or_declare(ccroot.get_target_name(program_obj)).abspath(env)
- out = open(os.path.join('..', 'doc', 'introspected-doxygen.h'), 'w')
- if subprocess.Popen([prog], stdout=out, env=proc_env).wait():
+
+ # Create a header file with the introspected information.
+ doxygen_out = open(os.path.join('doc', 'introspected-doxygen.h'), 'w')
+ if subprocess.Popen([prog], stdout=doxygen_out, env=proc_env).wait():
raise SystemExit(1)
- out.close()
+ doxygen_out.close()
+
+ # Create a text file with the introspected information.
+ text_out = open(os.path.join('doc', 'ns3-object.txt'), 'w')
+ if subprocess.Popen([prog, '--output-text'], stdout=text_out, env=proc_env).wait():
+ raise SystemExit(1)
+ text_out.close()
class run_python_unit_tests_task(Task.TaskBase):
- after = 'cc cxx cc_link cxx_link'
+ after = 'cc cxx link'
color = 'BLUE'
def __init__(self, bld):
@@ -952,24 +950,34 @@
"You should correct this situation before running any program. Possible solutions:\n"
" 1. Exit this shell, and start a new one\n"
" 2. Run a new nested shell")
- raise Utils.WafError(msg)
+ raise WafError(msg)
-shell_context = Build.BuildContext
-def shell(ctx):
+from waflib import Context, Build
+class Ns3ShellContext(Context.Context):
"""run a shell with an environment suitably modified to run locally built programs"""
+ cmd = 'shell'
- #make sure we build first"
- Scripting.build(ctx)
+ def execute(self):
+
+ # first we execute the build
+ bld = Context.create_context("build")
+ bld.options = Options.options # provided for convenience
+ bld.cmd = "build"
+ bld.execute()
- if sys.platform == 'win32':
- shell = os.environ.get("COMSPEC", "cmd.exe")
- else:
- shell = os.environ.get("SHELL", "/bin/sh")
+ if sys.platform == 'win32':
+ shell = os.environ.get("COMSPEC", "cmd.exe")
+ else:
+ shell = os.environ.get("SHELL", "/bin/sh")
- env = wutils.bld.env
- os_env = {'NS3_MODULE_PATH': os.pathsep.join(env['NS3_MODULE_PATH']), 'NS3_EXECUTABLE_PATH': os.pathsep.join(env['NS3_EXECUTABLE_PATH'])}
- wutils.run_argv([shell], env, os_env)
+ env = bld.env
+ os_env = {
+ 'NS3_MODULE_PATH': os.pathsep.join(env['NS3_MODULE_PATH']),
+ 'NS3_EXECUTABLE_PATH': os.pathsep.join(env['NS3_EXECUTABLE_PATH']),
+ }
+ wutils.run_argv([shell], env, os_env)
+
def _doxygen(bld):
env = wutils.bld.env
@@ -987,7 +995,7 @@
raise SystemExit(1)
return
- prog = program_obj.path.find_or_declare(ccroot.get_target_name(program_obj)).abspath(env)
+ prog = program_obj.path.find_or_declare(program_obj.target).abspath()
if not os.path.exists(prog):
Logs.error("print-introspected-doxygen has not been built yet."
@@ -995,43 +1003,57 @@
"generating doxygen docs...")
raise SystemExit(1)
- out = open(os.path.join('doc', 'introspected-doxygen.h'), 'w')
+ # Create a header file with the introspected information.
+ doxygen_out = open(os.path.join('doc', 'introspected-doxygen.h'), 'w')
+ if subprocess.Popen([prog], stdout=doxygen_out, env=proc_env).wait():
+ raise SystemExit(1)
+ doxygen_out.close()
- if subprocess.Popen([prog], stdout=out, env=proc_env).wait():
+ # Create a text file with the introspected information.
+ text_out = open(os.path.join('doc', 'ns3-object.txt'), 'w')
+ if subprocess.Popen([prog, '--output-text'], stdout=text_out, env=proc_env).wait():
raise SystemExit(1)
- out.close()
+ text_out.close()
doxygen_config = os.path.join('doc', 'doxygen.conf')
if subprocess.Popen([env['DOXYGEN'], doxygen_config]).wait():
raise SystemExit(1)
-def doxygen(bld):
- """do a full build, generate the introspected doxygen and then the doxygen"""
- Scripting.build(bld)
- _doxygen(bld)
+
+from waflib import Context, Build
-def lcov_report():
- env = Build.bld.env
- variant_name = env['NS3_ACTIVE_VARIANT']
+class Ns3DoxygenContext(Context.Context):
+ """do a full build, generate the introspected doxygen and then the doxygen"""
+ cmd = 'doxygen'
+ def execute(self):
+ # first we execute the build
+ bld = Context.create_context("build")
+ bld.options = Options.options # provided for convenience
+ bld.cmd = "build"
+ bld.execute()
+ _doxygen(bld)
+
- if 'gcov' not in variant_name:
- raise Utils.WafError("project not configured for code coverage;"
- " reconfigure with --enable-gcov")
+
+def lcov_report(bld):
+ env = bld.env
- os.chdir(blddir)
+ if not env['GCOV_ENABLED']:
+ raise WafError("project not configured for code coverage;"
+ " reconfigure with --enable-gcov")
+
+ os.chdir(out)
try:
- lcov_report_dir = os.path.join(variant_name, 'lcov-report')
+ lcov_report_dir = 'lcov-report'
create_dir_command = "rm -rf " + lcov_report_dir
create_dir_command += " && mkdir " + lcov_report_dir + ";"
if subprocess.Popen(create_dir_command, shell=True).wait():
raise SystemExit(1)
- info_file = os.path.join(lcov_report_dir, variant_name + '.info')
+ info_file = os.path.join(lcov_report_dir, 'report.info')
lcov_command = "../utils/lcov/lcov -c -d . -o " + info_file
- lcov_command += " --source-dirs=" + os.getcwd()
- lcov_command += ":" + os.path.join(
- os.getcwd(), variant_name, 'include')
+ lcov_command += " -b " + os.getcwd()
if subprocess.Popen(lcov_command, shell=True).wait():
raise SystemExit(1)
@@ -1042,116 +1064,3 @@
finally:
os.chdir("..")
-##
-## The default WAF DistDir implementation is rather slow, because it
-## first copies everything and only later removes unwanted files and
-## directories; this means that it needless copies the full build dir
-## and the .hg repository tree. Here we provide a replacement DistDir
-## implementation that is more efficient.
-##
-import Scripting
-from Scripting import dist_exts, excludes, BLDDIR
-import Utils
-import os
-
-def _copytree(src, dst, symlinks=False, excludes=(), build_dir=None):
- """Recursively copy a directory tree using copy2().
-
- The destination directory must not already exist.
- If exception(s) occur, an Error is raised with a list of reasons.
-
- If the optional symlinks flag is true, symbolic links in the
- source tree result in symbolic links in the destination tree; if
- it is false, the contents of the files pointed to by symbolic
- links are copied.
-
- XXX Consider this example code rather than the ultimate tool.
-
- Note: this is a modified version of shutil.copytree from python
- 2.5.2 library; modified for WAF purposes to exclude dot dirs and
- another list of files.
- """
- names = os.listdir(src)
- os.makedirs(dst)
- errors = []
- for name in names:
- srcname = os.path.join(src, name)
- dstname = os.path.join(dst, name)
- try:
- if symlinks and os.path.islink(srcname):
- linkto = os.readlink(srcname)
- os.symlink(linkto, dstname)
- elif os.path.isdir(srcname):
- if name in excludes:
- continue
- elif name.startswith('.') or name.startswith(',,') or name.startswith('++') or name.startswith('CVS'):
- continue
- elif name == build_dir:
- continue
- else:
- ## build_dir is not passed into the recursive
- ## copytree, but that is intentional; it is a
- ## directory name valid only at the top level.
- copytree(srcname, dstname, symlinks, excludes)
- else:
- ends = name.endswith
- to_remove = False
- if name.startswith('.') or name.startswith('++'):
- to_remove = True
- else:
- for x in dist_exts:
- if ends(x):
- to_remove = True
- break
- if not to_remove:
- shutil.copy2(srcname, dstname)
- # XXX What about devices, sockets etc.?
- except (IOError, os.error), why:
- errors.append((srcname, dstname, str(why)))
- # catch the Error from the recursive copytree so that we can
- # continue with other files
- except shutil.Error, err:
- errors.extend(err.args[0])
- try:
- shutil.copystat(src, dst)
- except WindowsError:
- # can't copy file access times on Windows
- pass
- except OSError, why:
- errors.extend((src, dst, str(why)))
- if errors:
- raise shutil.Error, errors
-
-
-def DistDir(appname, version):
- #"make a distribution directory with all the sources in it"
- import shutil
-
- # Our temporary folder where to put our files
- TMPFOLDER=appname+'-'+version
-
- # Remove an old package directory
- if os.path.exists(TMPFOLDER): shutil.rmtree(TMPFOLDER)
-
- global g_dist_exts, g_excludes
-
- # Remove the Build dir
- build_dir = getattr(Utils.g_module, BLDDIR, None)
-
- # Copy everything into the new folder
- _copytree('.', TMPFOLDER, excludes=excludes, build_dir=build_dir)
-
- # TODO undocumented hook
- dist_hook = getattr(Utils.g_module, 'dist_hook', None)
- if dist_hook:
- os.chdir(TMPFOLDER)
- try:
- dist_hook()
- finally:
- # go back to the root directory
- os.chdir('..')
- return TMPFOLDER
-
-Scripting.DistDir = DistDir
-
-
--- a/wutils.py Sat Aug 20 14:41:19 2011 -0400
+++ b/wutils.py Mon Oct 17 16:59:17 2011 -0400
@@ -1,18 +1,17 @@
import os
import os.path
import sys
-import pproc as subprocess
+import subprocess
import shlex
# WAF modules
-import ccroot
import Options
import Utils
import Logs
import TaskGen
import Build
import re
-
+from waflib.Errors import WafError
# these are set from the main wscript file
APPNAME=None
@@ -48,10 +47,10 @@
return os.path.curdir
return os.path.join(*rel_list)
-
+from waflib import Context
def find_program(program_name, env):
- launch_dir = os.path.abspath(Options.cwd_launch)
- top_dir = os.path.abspath(Options.launch_dir)
+ launch_dir = os.path.abspath(Context.launch_dir)
+ #top_dir = os.path.abspath(Options.cwd_launch)
found_programs = []
for obj in bld.all_task_gen:
if not getattr(obj, 'is_ns3_program', False):
@@ -63,7 +62,7 @@
continue
name1 = obj.target
- name2 = os.path.join(relpath(obj.path.abspath(), top_dir), obj.target)
+ name2 = os.path.join(relpath(obj.path.abspath(), launch_dir), obj.target)
names = [name1, name2]
found_programs.extend(names)
if program_name in names:
@@ -99,7 +98,7 @@
else:
proc_env[pathvar] = os.pathsep.join(list(env['NS3_MODULE_PATH']))
- pymoddir = bld.path.find_dir('bindings/python').abspath(env)
+ pymoddir = bld.path.find_dir('bindings/python').get_bld().abspath()
pyvizdir = bld.path.find_dir('src/visualizer').abspath()
if 'PYTHONPATH' in proc_env:
proc_env['PYTHONPATH'] = os.pathsep.join([pymoddir, pyvizdir] + [proc_env['PYTHONPATH']])
@@ -117,9 +116,9 @@
proc_env = get_proc_env(os_env)
if Options.options.valgrind and not force_no_valgrind:
if Options.options.command_template:
- raise Utils.WafError("Options --command-template and --valgrind are conflicting")
+ raise WafError("Options --command-template and --valgrind are conflicting")
if not env['VALGRIND']:
- raise Utils.WafError("valgrind is not installed")
+ raise WafError("valgrind is not installed")
argv = [env['VALGRIND'], "--leak-check=full", "--show-reachable=yes", "--error-exitcode=1"] + argv
proc = subprocess.Popen(argv, env=proc_env, cwd=cwd, stderr=subprocess.PIPE)
error = False
@@ -139,7 +138,7 @@
try:
retval = subprocess.Popen(argv, env=proc_env, cwd=cwd).wait()
except WindowsError, ex:
- raise Utils.WafError("Command %s raised exception %s" % (argv, ex))
+ raise WafError("Command %s raised exception %s" % (argv, ex))
if retval:
signame = None
if retval < 0: # signal?
@@ -150,11 +149,11 @@
signame = name
break
if signame:
- raise Utils.WafError("Command %s terminated with signal %s."
+ raise WafError("Command %s terminated with signal %s."
" Run it under a debugger to get more information "
"(./waf --run <program> --command-template=\"gdb --args %%s <args>\")." % (argv, signame))
else:
- raise Utils.WafError("Command %s exited with code %i" % (argv, retval))
+ raise WafError("Command %s exited with code %i" % (argv, retval))
return retval
def get_run_program(program_string, command_template=None):
@@ -173,15 +172,15 @@
try:
program_obj = find_program(program_name, env)
except ValueError, ex:
- raise Utils.WafError(str(ex))
+ raise WafError(str(ex))
- program_node = program_obj.path.find_or_declare(ccroot.get_target_name(program_obj))
+ program_node = program_obj.path.find_or_declare(program_obj.target)
#try:
# program_node = program_obj.path.find_build(ccroot.get_target_name(program_obj))
#except AttributeError:
# raise Utils.WafError("%s does not appear to be a program" % (program_name,))
- execvec = [program_node.abspath(env)] + argv[1:]
+ execvec = [program_node.abspath()] + argv[1:]
else:
@@ -189,15 +188,15 @@
try:
program_obj = find_program(program_name, env)
except ValueError, ex:
- raise Utils.WafError(str(ex))
+ raise WafError(str(ex))
- program_node = program_obj.path.find_or_declare(ccroot.get_target_name(program_obj))
+ program_node = program_obj.path.find_or_declare(program_obj.target)
#try:
# program_node = program_obj.path.find_build(ccroot.get_target_name(program_obj))
#except AttributeError:
# raise Utils.WafError("%s does not appear to be a program" % (program_name,))
- tmpl = command_template % (program_node.abspath(env),)
+ tmpl = command_template % (program_node.abspath(),)
execvec = shlex.split(tmpl.replace('\\', '\\\\'))
#print "%r ==shlex.split==> %r" % (command_template % (program_node.abspath(env),), execvec)
return program_name, execvec
@@ -230,5 +229,92 @@
cwd = Options.cwd_launch
if visualize:
execvec.append("--SimulatorImplementationType=ns3::VisualSimulatorImpl")
- return run_argv([env['PYTHON']] + execvec, env, cwd=cwd)
+ return run_argv([env['PYTHON'][0]] + execvec, env, cwd=cwd)
+
+
+
+def monkey_patch_Runner_start():
+ """http://code.google.com/p/waf/issues/detail?id=1039"""
+ from waflib import Task
+ def start(self):
+ """
+ Give tasks to :py:class:`waflib.Runner.TaskConsumer` instances until the build finishes or the ``stop`` flag is set.
+ If only one job is used, then execute the tasks one by one, without consumers.
+ """
+
+ self.total = self.bld.total()
+
+ while not self.stop:
+
+ self.refill_task_list()
+
+ # consider the next task
+ tsk = self.get_next_task()
+ if not tsk:
+ if self.count:
+ # tasks may add new ones after they are run
+ continue
+ else:
+ # no tasks to run, no tasks running, time to exit
+ break
+
+ if tsk.hasrun:
+ # if the task is marked as "run", just skip it
+ self.processed += 1
+ continue
+
+ if self.stop: # stop immediately after a failure was detected
+ break
+ try:
+ st = tsk.runnable_status()
+ except Exception:
+ self.processed += 1
+ if not self.stop and self.bld.keep:
+ tsk.hasrun = Task.SKIPPED
+ if self.bld.keep == 1:
+ # if -k stop at the first exception, if -kk try to go as far as possible
+ self.stop = True
+ continue
+ tsk.err_msg = Utils.ex_stack()
+ tsk.hasrun = Task.EXCEPTION
+ self.error_handler(tsk)
+ continue
+
+ if st == Task.ASK_LATER:
+ self.postpone(tsk)
+ # TODO optimize this
+ # if self.outstanding:
+ # for x in tsk.run_after:
+ # if x in self.outstanding:
+ # self.outstanding.remove(x)
+ # self.outstanding.insert(0, x)
+ elif st == Task.SKIP_ME:
+ self.processed += 1
+ tsk.hasrun = Task.SKIPPED
+ self.add_more_tasks(tsk)
+ else:
+ # run me: put the task in ready queue
+ tsk.position = (self.processed, self.total)
+ self.count += 1
+ tsk.master = self
+ self.processed += 1
+
+ if self.numjobs == 1:
+ tsk.process()
+ else:
+ self.add_task(tsk)
+
+ # self.count represents the tasks that have been made available to the consumer threads
+ # collect all the tasks after an error else the message may be incomplete
+ while self.error and self.count:
+ self.get_out()
+
+ #print loop
+ assert (self.count == 0 or self.stop)
+
+ # free the task pool, if any
+ self.free_task_pool()
+
+ from waflib.Runner import Parallel
+ Parallel.start = start