转自http://blog.csdn.net/and_w/article/details/61619241
本节的目的是让用户在一个从未安装过 ns-3 的机器上进入工作状态。 它涵盖了支持平台、前提条件、获取 ns-3 的方法,构建 ns-3 的方法,以及验证你构建的系统和运行简单的程序。
ns-3 被构建为能够协同工作的软件库系统。可以编写链接这些库的(或导入这些库的)用户程序。用户程序既可用 C++ 也可 Python 编写。
ns-3 以源码形式发布,这意味着目标系统需要有软件开发环境能够首先构建所需的库,然后构建用户程序。ns-3 在原则上能以所选系统预编译库形式发布,嗯,在将来她可能会以这种形式发布。,但在目前,很多用户实际上编辑的是 ns-3 本身,所以有源代码在对他们的工作很有帮助。如果有人想要为操作系统提供预编译的库和包,请联系 ns 开发者的 mailing list。
接下来,我们将看看下载和构建 ns-3 的两种方式。第一种是在主站点下载并构建正式版。第二种是获取并构建开发版。我们将通过两个例子演示,因为涉及的工具略有不同。
ns-3 系统就整体来看是一个相当复杂的系统并与多个其他组件具有依赖关系。除了你可能每天都要打交道的系统(GNU 工具链、文本编辑器、Mercurial),在继续之前,你还需要确保系统上存在多个附加库。ns-3 提供了包括很多有用提示和技巧(hint and tip)的 WiKi。其中一个这样的页面是“安装”页,http://www.nsnam.org/wiki/Installation 。
这个 WiKi 页面的“前提条件”部分解释了支持常见 ns-3 选项需要哪些包,并提供了在常见 Linux 发行版安装它们的命令。 Cygwin 用户须使用 Cygwin 安装器(如果你是 Cygwin 用户,你用它安装 Cygwin)。
你可能想借此机会探索 ns-3 WiKi,因为那儿真的有丰富的信息。
从这一点出发,我们将假设读者在 linux 或 linux 仿真环境(Linux,Cygwin 等)下工作,并且已经安装了 GNU 工具链,验证安装了上述“前提条件”。我们还将假设你已在目标系统上安装并运行了 Mercurial 和 Waf。
ns-3 的代码在 Mercurial 的仓库上,服务器是 http://code.nsnam.org 。你也可以下载压缩文件 http://www.nsnam.org/release/ ,或者你也可以使用 Mercurial。 我们建议你使用 Mercurial,除非你有一个很好的理由不这么做。有关如何获取压缩包的说明,请参阅本节末尾。
开始 Mercurial 仓库最简单的方法是使用 ns-3-allinone
环境。这是一组为你管理下载和构建各种 ns-3 子系统的脚本。我们建议你在此环境下开始你的 ns-3 工作。
一种做法是,在 home 目录下创建名为 workspace
的目录,在该目录保持局部 Mercurial 仓库。当然任何其他目录名都可以,但在此我们假设使用 workspace
(注:repos
有时也在一些文档中被用作示例目录名)。
tarball 是一种软件存档的特殊格式,存档中多个文件被捆绑在一起并且这种存档可能是被压缩的。ns-3 提供了可下载的 tarball 压缩包。通过压缩包下载 ns-3 的过程很简单,你只需要选择一个版本,下载并解压就行了。
假设你作为一个用户,希望在名为 workspace
的本地目录下构建 ns-3。如果你采用 workspace
目录法,你可以通过在你的 linux shell 里键入以下命令(当然要替换相应的版本号)获取一个副本:
如果您进入到目录 ns-allinone-3.26
,你应该看到一些文件和目录:
你现在随时可以构建基础的 ns-3 发行版,并且可以直接跳到构建 ns-3 那一节。
Bake 是为 ns-3 项目而开发的分布式集成和构建工具。Bake 可用于获取 ns-3 软件的开发版本,并用于下载和构建基础 ns-3 发行版的扩展,如 DCE 环境、Network Simulation Cradle、创建新的 Python 包以及其他。
在最近的 ns-3 版本中 Bake 已经包含在压缩包中。其配置文件允许用户下载当前版本发布时存在的任何软件。也就是说,例如,ns-3.21
版的 Bake 可以用来获取该版及更低版的组件,但不能用来更高版本的组件(除非 bakeconf.xml 文件被更新)。
你也可以通过在你的 linux shell 里键入以下命令(假设你已经安装了 Mercurial)获取最新 Bake 副本:
当 hg(Mercurial)命令执行时,你应该看到类似如下面显示的内容:
clone 命令完成后,你应该有一个目录叫 bake
,其中应类似如下面的内容:
请注意,你真的只是下载了一些 Python 脚本和一个叫 bake
的 Python 模块。接下来的步骤是使用这些脚本下载并构建你选择的 ns-3 发行版。
有几个可选的配置目标:
ns-3.26
:对应于发布版的模块,它会下载类似发布版压缩包的组件。ns-3-dev
:同上面的类似,但它使用的是开发代码树。ns-allinone-3.26
:包括其他可选功能,如点击路由、openflow for ns-3 以及 Network Simulation Cradle。ns-3-allinone
:同上类似,但使用的是开发代码。ns-3 开发中快照(未发行)可以在 http://code.nsnam.org/ns-3-dev/ 找到。开发人员试图使这些仓库处于一致的状态,但它们处在未发布代码开发区。所以如果你不需要引入的新功能,你可能需要的是一个正式版。
你既可以通过检查仓库列表获取最新版代码,也可以通过在 ns-3 Releases 网页点击最新发布版链接获取最新版代码。我们将使用 ns-3.26
作为例子继续本教程。
现在,我们将使用 bake 工具拉取你将要使用的 ns-3 的各个部分。 首先,我们将介绍一下如何运行 bake。
bake 通过将源码包下载到源目录并将库安装到编译目录来工作。bake 可以通过引用二进制文件来运行,但如果选择从它(被下载到的目录)以外运行 bake,我们建议将 bake 加入到你的 path,如下所示(以 linux bash shell 作为例子)。首先,切换到 bake 目录,然后设置以下环境变量:
这会将 bake.py 程序放到 shell 的 path 中,并允许其他程序找到由 bake 创建的可执行文件和库。虽然仅仅几个 bake 用例并不需要如上所述设置 PATH 和 PYTHONPATH,但是完整的构建 ns-3-allinone(使用可选软件包)通常需要这么做。
进入workspace 目录并在 shell 中键入以下内容:
接下来,我们需要 bake 检查我们是否有足够的工具来下载各种组件。键入:
你应该看到如下内容:
特别的,下载工具如 Mercurial、CVS、Git 和 Bazaar 是我们在此时主要关注的,因为它们可以为我们获取代码。请在此阶段以你的系统常见的方式安装(如果你能够做到的话)缺少的工具,或者根据需要与系统管理员联系以安装这些工具。
接下来,尝试下载软件:
应该会生成一些如下的东西:
以上表明已经下载了五个来源文件。 现在检查 source
目录,输入ls,应该可以看到:
现在你随时可以构建 ns-3 发行版了。
当你从发布版的 tarball 开始时,首次构建 ns-3 可以使用 allinone
目录下的一个便捷程序。该程序被称为 build.py。该程序将以最常见有用的方式为你配置本项目。但是,请注意,更先进的配置和使用 ns-3 的方式是使用 ns-3 原生的构建系统——Waf。Waf 将在本教程后面介绍。
如果你是用 tarball 下载的,你应该在你的 ~/workspace
目录下看到像 ns-allinone-3.26
之类的文件夹。键入以下内容:
因为本教程是基于实例和测试的,也因为它们不是构建 ns-3 的默认选项,这些参数告诉 build.py 为我们构建它们。该程序还默认构建所有可用的模块。以后如果你愿意,你可以不基于实例和测试构建 ns-3,也可以取消对你的工作不必要的模块。
您将看到许多典型的编译器输出消息,显示的是构建脚本构建你下载的各种内容的信息。最终你应该看到以下内容:
关于未被构建模块的部分:
这只是意味着某些 ns-3 模块依赖的外部库可能尚未安装,或者配置文件专门指定不构建它们。这并不意味着模拟器没有成功构建,也不意味着其会对正在构建的(被列出的)模块给出错误的结果。
如果你之前是用 bake 从项目仓库获取源代码的,那么你可以继续使用它来构建 ns-3。键入:
你应该可看见如下信息:
提示:你可以通过调用 bake.py deploy
,一次性执行下载和构建这两步。
如果出现错误,可以执行下面命令,它会告诉你缺少的依赖关系:
这将列出你正在尝试构建的包的各种依赖关系。
到目前为止,我们既可以使用 build.py 脚本也可以使用 bake 工具开始构建 ns-3。 这些工具对构建 ns-3 和其支持库都是有帮助的,它们进入 ns-3 目录调用 Waf 构建工具做实际的构建。大多数用户快速过渡到直接使用 Waf 配置和构建 ns-3。因此,要继续的话,请将你的工作目录换成已初步建成 ns-3 目录。
在这一点上并不是严格要求的,但稍稍绕路并看看如何更改项目的配置文件也是很有价值的。也许,你做出的配置更改最有用的地方是将构建代码的优化(optimized)版。 默认情况下,你对项目的配置是构建 debug 版。让我们告诉项目做构建优化。要向 Waf 解释它应该做包括了实例和测试的构建优化,你需要执行以下命令:
这将从本地目录运行 Waf(这为你提供了方便)。第一条命令清除以前的版本,它通常不是绝对必要的,但它是很好的做法(参阅 Build Profiles), 它会删除以前建的库和在 build/
目录下找到的目标文件。当重新配置项目并构建系统检查各种依赖关系时,你应该看到类似如下输出:
注意上面输出的最后一部分。有些 ns-3 的选项默认未启用(not enable),或者需要底层系统的支持才能正常工作。 例如,要启用(enable) XmlTo,必须在系统上找到库 libxml-2.0。 如果没有发现这个库,相应的 ns-3 功能将不会被启用,并显示一条消息。进一步需要注意的是这里有一个特性是对特定程序使用 sudo
设置 suid 位。它默认是未启用的,因此这个特性被报告为“未启用”。最后,如果要重新打印哪些选项被启用的报告,对 Waf 使用 –check-config 选项。
现在继续,切换回包括了实例和测试的 debug 版:
现在,构建系统已经配置好了,你可以构建 ns-3 程序的 debug 版,通过输入:
好了,抱歉,我让你构建了系统的 ns-3 部分两次,但现在你应该知道了如何更改配置和构建优化的代码。
有一个用于检查(已配置项目)当前哪些 profile 处于活动状态的命令:
上面讨论的 build.py 脚本也支持 --enable-examples
和 --enable-tests
参数,但在一般情况下,不直接支持其他 Waf 选项。例如,这不会生效:
将导致
然而,特殊运算符 – 可用于通过 Waf 传附加选项,所以下面将会生效:
因为它会产生下层命令 ./waf configure --disable-python
。
这里有几个关于 Waf 的介绍性提示
一些 Waf 命令只在配置(configure)阶段有意义,一些命令则在构建(build)阶段有效。例如,如果你想使用 ns-3 的仿真功能,你可能希望启用如上所述的使用 sudo 设置 suid 位功能。 这原来是配置时(configuration-time)命令,因此你可以使用以下命令重新配置(也包括实例和测试)。
如果这样做,Waf 将使用 sudo,以 root 身份运仿真代码的套接字(socket)创建程序。
Waf 中还有许多其他配置时和构建时选项。要浏览这些选项,请键入:
我们将在下一节中使用一些测试相关(testing-related)的命令。
我们已经看到如何使用 Waf 配置 debug
和 optimized
版:
此外,还有一个中间版的 profile,release
。-d
与 --build-profile
同义。
Build profile 控制日志记录(logging)、声明(assertion)和编译器优化(compiler optimization)的使用:
Feature | Build profile | ||
---|---|---|---|
debug | release | optimized | |
Enabled Features | NS3_BUILD_PROFILE_DEBUG NS_LOG… NS_ASSERT… |
NS3_BUILD_PROFILE_RELEASE | NS3_BUILD_PROFILE_OPTIMIZED |
Code Wrapper Macro | NS_BUILD_DEBUG(code) | NS_BUILD_RELEASE(code) | NS_BUILD_OPTIMIZED(code) |
Compiler Flags | -O0 -ggdb -g3 | -O3 -g0 -fomit-frame-pointer | -O3 -g -fstrict-overflow -march=native |
如你所见,日志和声明仅在调试(debug)版中可用。建议做法是在调试模式下开发场景(scenario),然后在优化模式中重复运行(用于统计或更改参数)。
如果你的代码只在特定 build profile 中运行,请指明代码包装宏(Code Wrapper Macro):
默认情况下 Waf 将生成的文件放在 build
目录下。你可以用 –out 选项指定不同的输出目录:
将它与 build profile 相结合,你可以用干净的方式切换不同的编译选项:
这允许你使用多个版本,而不是总是覆盖最后一个版本。当你切换时,Waf 只会编译它所具有,而不是重新编译的一切。
当你这样切换时,你必须小心地每次给出相同的配置参数。定义一些环境变量更加便捷也能够避免错误:
在上面的例子中,Waf 使用 GCC C++ 编译器,g++
,构建 ns-3。 然而,可以通过定义 CXX
环境变量来改变 Waf 使用的 C++ 编译器。 例如,使用 Clang C++ 编译器,clang++
,
人们也可以以类似的方式设置 Waf 为 distcc
做分布式编译:
关于 distcc
和分布式编译的更多信息可以在它的项目页中的文档部分找到。
要添加编译器标志,在配置 ns-3 时使用 CXXFLAGS_EXTRA
环境变量。
Waf 可以用于在系统的各个地方安装库。其中,库和可执行文件的默认位置是 build
目录,而且由于 Waf 知道这些库和可执行文件的位置,没有必要在其他地方安装库。
如果用户选择在 build
目录外安装,用户可以使用 ./waf install
命令。默认情况下,前缀(prefix)是 /usr/local
,所以 ./waf install
将程序安装到 /usr/local/bin
目录 ,将库安装到 /usr/local/lib
目录 ,将头文件安装到 usr/local/include
目录。 超级用户权限通常需要安装到默认前缀,因此,通常的命令是 sudo ./waf install
。当使用 Waf 运行程序时,Waf 首先使用 build
目录下的共享库,然后在本地环境中配置的库路径中查找库。因此,在将库安装到系统时,最好检查所需库是否正在被使用。
用户可以在配置时通过 --prefix
将文件安装到不同的前缀:
在以后的版本中用户发出 ./waf install
命令,前缀 /opt/local
将被使用。
在重新配置项目之前应该先使用 ./waf clean
命令,如果 Waf 被用来在不同目录下安装东西的话。
总之,使用 ns-3 是没有必要调用 ./waf install
的。大多数用户不需要此命令,因为 Waf 将从 build
目录拿出当前库,但一些用户可能会发现,如果他们的用例涉及 ns-3 目录外的程序时它很有用。
这里只有一个 Waf 脚本,它在 ns-3 源码树(source tree)的顶层。当你工作时,你会发现自己花费了大量的时间在 scratch/
或深层 src/...
,并且需要调用 Waf。你可以记住你在哪里,并像这样调用 Waf:
这会变得冗长乏味,容易出错,还有更好的解决方案。
如果你有完整的 ns-3 仓库,下面这个小技巧是开始:
当然,将其定义为 shell 函数更好:
如果你只有 tarball,设置环境变量会有帮助:
在模块的目录下添加一个简单 Waf 脚本 exec ../../waf
可能是很诱人的想法。但请不要这么做。它会让新用户感到困惑,当做得不好时,会导致微妙的构建错误。上面的解决方案才是要走的路。
你可以通过运行 ./test.py -c cora
脚本对 ns-3 进行单元测试:
这些测试由 Waf 并行运行。你最终应该看到一个报告说:
这是重要的信息。
你还会看到 Waf 和测试运行器执行每个测试的摘要输出,它看起来像这样:
这个命令一般是用户用来快速验证 ns-3 是否正确构建的。(注意 PASS:...
的顺序可能会有所不同,这是可以的。重要的是,在最后的总结行的报告说,所有测试都通过没有失败或崩溃的。)
我们通常在 Waf 的控制下运行脚本。这将确保共享库路径设置正确,并且库在运行时可用。要运行一个程序,只需使用 Waf 的 --run
选项。让我们通过键入以下命令运行 ns-3 的 Hello World 程序:
Waf 首先执行检查以确保程序已正确构建,并在需要时执行构建。然后执行该程序,产生以下输出:
恭喜!你现在是一位 ns-3 用户了!
如果我看不到输出怎么办?
如果你看到 Waf 提示构建已成功完成,但却没有看到“Hello Simulator”输出,可能是因为,你在 Building with Waf 那一节切换构建模式为 optimized
,但忘了切回 debug
模式。本教程中使用的所有的控制台输出都采用了特殊的 ns-3 日志记录组件,对打印用户消息到控制台非常有用。当你编译优化代码时,此组件的输出将自动禁用——它是“优化输出的”。如果你没有看到“Hello Simulator”输出,请键入以下内容:
为了告诉 Waf 构建包含实例和测试的 debug 版 ns-3。你仍然需要构建代码实际上的 debug 版,键入:
现在,如果你运行 hello-simulator
程序,你应该看到预期的输出。
向 ns-3 程序提供命令行参数,使用下面这种模式:
将
替换为你程序的名称,
替换为你的参数。Waf 的 --command-template
是用来为 Waf 构造实际的命令行,Waf 通过该命令行执行程序。Waf 检查到程序构建完成,设置共享库路径,然后使用所提供的命令行模板(command line template),将程序名插入 %s
占位符,调用可执行程序。(我承认这有点笨拙,但这就是它的工作方式。欢迎补丁!)
另一个特别有用的例子是运行它自己的测试套件。假设存在一个 mytest
测试套件(事实并非如此)。在上面,我们使用 ./test.py
脚本(通过反复调用真正的测试程序,test-runner
)并行运行了全系列的测试。对单一测试直接调用 test-runner
,使用:
这将传参数给 test-runner
程序。因为 mytest
不存在,将产生一个错误信息。要打印可用的 test-runner
选项,使用:
若要在其他单元的控制下运行 ns-3 程序,如调试器(gdb
)或内存检查(valgrind
),你可以使用类似 --command-template="..."
的格式。
例如,在 gdb
调试器下运行带参数
的 ns-3 程序 hello-simulator
:
请注意,ns-3的程序名紧随 --run
参数,控制程序(这里是 gdb
)是 --commmand-template
参数的第一块。--args
参数告诉 gdb
该命令行的其余部分属于“下级”程序。 (某些 gdb
不能解析 --args
参数。在这种情况下,在 --command-template
中省略程序参数,并使用 gdb
命令的 set args
参数)。
我们可以结合这个和前面的一个在调试器下运行测试:
Waf 需要在 ns-3 目录树的顶部位置运行。这会成为工作目录,输出文件会被写入其中。但是,如果你想将哪些输出文件写到 ns-3 的 source 树呢?使用 --cwd
参数:
将输出文件所在的地方当成工作目录可能更方便,在这种情况下,使用间接的方法可能会有帮助:
这会保存当前的工作目录,cd
到 Waf 目录,然后指示 Waf 在运行程序之前,将工作目录切回到已保存的当前工作目录。