A Discrete-Event Network Simulator
API
create-module.py
Go to the documentation of this file.
1 #! /usr/bin/env python3
2 from __future__ import print_function
3 import sys
4 from optparse import OptionParser
5 import os
6 
7 
8 WSCRIPT_TEMPLATE = '''# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
9 
10 # def options(opt):
11 # pass
12 
13 # def configure(conf):
14 # conf.check_nonfatal(header_name='stdint.h', define_name='HAVE_STDINT_H')
15 
16 def build(bld):
17  module = bld.create_ns3_module(%(MODULE)r, ['core'])
18  module.source = [
19  'model/%(MODULE)s.cc',
20  'helper/%(MODULE)s-helper.cc',
21  ]
22 
23  module_test = bld.create_ns3_module_test_library('%(MODULE)s')
24  module_test.source = [
25  'test/%(MODULE)s-test-suite.cc',
26  ]
27 
28  headers = bld(features='ns3header')
29  headers.module = %(MODULE)r
30  headers.source = [
31  'model/%(MODULE)s.h',
32  'helper/%(MODULE)s-helper.h',
33  ]
34 
35  if bld.env.ENABLE_EXAMPLES:
36  bld.recurse('examples')
37 
38  # bld.ns3_python_bindings()
39 
40 '''
41 
42 
43 
44 MODEL_CC_TEMPLATE = '''/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
45 
46 #include "%(MODULE)s.h"
47 
48 namespace ns3 {
49 
50 /* ... */
51 
52 
53 }
54 
55 '''
56 
57 
58 
59 MODEL_H_TEMPLATE = '''/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
60 #ifndef %(INCLUDE_GUARD)s
61 #define %(INCLUDE_GUARD)s
62 
63 namespace ns3 {
64 
65 /* ... */
66 
67 }
68 
69 #endif /* %(INCLUDE_GUARD)s */
70 
71 '''
72 
73 
74 
75 HELPER_CC_TEMPLATE = '''/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
76 
77 #include "%(MODULE)s-helper.h"
78 
79 namespace ns3 {
80 
81 /* ... */
82 
83 
84 }
85 
86 '''
87 
88 
89 
90 HELPER_H_TEMPLATE = '''/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
91 #ifndef %(INCLUDE_GUARD)s
92 #define %(INCLUDE_GUARD)s
93 
94 #include "ns3/%(MODULE)s.h"
95 
96 namespace ns3 {
97 
98 /* ... */
99 
100 }
101 
102 #endif /* %(INCLUDE_GUARD)s */
103 
104 '''
105 
106 
107 EXAMPLES_WSCRIPT_TEMPLATE = '''# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
108 
109 def build(bld):
110  obj = bld.create_ns3_program('%(MODULE)s-example', [%(MODULE)r])
111  obj.source = '%(MODULE)s-example.cc'
112 
113 '''
114 
115 EXAMPLE_CC_TEMPLATE = '''/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
116 
117 #include "ns3/core-module.h"
118 #include "ns3/%(MODULE)s-helper.h"
119 
120 using namespace ns3;
121 
122 
123 int
124 main (int argc, char *argv[])
125 {
126  bool verbose = true;
127 
128  CommandLine cmd;
129  cmd.AddValue ("verbose", "Tell application to log if true", verbose);
130 
131  cmd.Parse (argc,argv);
132 
133  /* ... */
134 
135  Simulator::Run ();
136  Simulator::Destroy ();
137  return 0;
138 }
139 
140 
141 '''
142 
143 
144 TEST_CC_TEMPLATE = '''/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
145 
146 // Include a header file from your module to test.
147 #include "ns3/%(MODULE)s.h"
148 
149 // An essential include is test.h
150 #include "ns3/test.h"
151 
152 // Do not put your test classes in namespace ns3. You may find it useful
153 // to use the using directive to access the ns3 namespace directly
154 using namespace ns3;
155 
156 // This is an example TestCase.
157 class %(CAPITALIZED)sTestCase1 : public TestCase
158 {
159 public:
160  %(CAPITALIZED)sTestCase1 ();
161  virtual ~%(CAPITALIZED)sTestCase1 ();
162 
163 private:
164  virtual void DoRun (void);
165 };
166 
167 // Add some help text to this case to describe what it is intended to test
168 %(CAPITALIZED)sTestCase1::%(CAPITALIZED)sTestCase1 ()
169  : TestCase ("%(CAPITALIZED)s test case (does nothing)")
170 {
171 }
172 
173 // This destructor does nothing but we include it as a reminder that
174 // the test case should clean up after itself
175 %(CAPITALIZED)sTestCase1::~%(CAPITALIZED)sTestCase1 ()
176 {
177 }
178 
179 //
180 // This method is the pure virtual method from class TestCase that every
181 // TestCase must implement
182 //
183 void
184 %(CAPITALIZED)sTestCase1::DoRun (void)
185 {
186  // A wide variety of test macros are available in src/core/test.h
187  NS_TEST_ASSERT_MSG_EQ (true, true, "true doesn't equal true for some reason");
188  // Use this one for floating point comparisons
189  NS_TEST_ASSERT_MSG_EQ_TOL (0.01, 0.01, 0.001, "Numbers are not equal within tolerance");
190 }
191 
192 // The TestSuite class names the TestSuite, identifies what type of TestSuite,
193 // and enables the TestCases to be run. Typically, only the constructor for
194 // this class must be defined
195 //
196 class %(CAPITALIZED)sTestSuite : public TestSuite
197 {
198 public:
199  %(CAPITALIZED)sTestSuite ();
200 };
201 
202 %(CAPITALIZED)sTestSuite::%(CAPITALIZED)sTestSuite ()
203  : TestSuite ("%(MODULE)s", UNIT)
204 {
205  // TestDuration for TestCase can be QUICK, EXTENSIVE or TAKES_FOREVER
206  AddTestCase (new %(CAPITALIZED)sTestCase1, TestCase::QUICK);
207 }
208 
209 // Do not forget to allocate an instance of this TestSuite
210 static %(CAPITALIZED)sTestSuite %(COMPOUND)sTestSuite;
211 
212 '''
213 
214 
215 DOC_RST_TEMPLATE = '''Example Module Documentation
216 ----------------------------
217 
218 .. include:: replace.txt
219 .. highlight:: cpp
220 
221 .. heading hierarchy:
222  ------------- Chapter
223  ************* Section (#.#)
224  ============= Subsection (#.#.#)
225  ############# Paragraph (no number)
226 
227 This is a suggested outline for adding new module documentation to |ns3|.
228 See ``src/click/doc/click.rst`` for an example.
229 
230 The introductory paragraph is for describing what this code is trying to
231 model.
232 
233 For consistency (italicized formatting), please use |ns3| to refer to
234 ns-3 in the documentation (and likewise, |ns2| for ns-2). These macros
235 are defined in the file ``replace.txt``.
236 
237 Model Description
238 *****************
239 
240 The source code for the new module lives in the directory ``src/%(MODULE)s``.
241 
242 Add here a basic description of what is being modeled.
243 
244 Design
245 ======
246 
247 Briefly describe the software design of the model and how it fits into
248 the existing ns-3 architecture.
249 
250 Scope and Limitations
251 =====================
252 
253 What can the model do? What can it not do? Please use this section to
254 describe the scope and limitations of the model.
255 
256 References
257 ==========
258 
259 Add academic citations here, such as if you published a paper on this
260 model, or if readers should read a particular specification or other work.
261 
262 Usage
263 *****
264 
265 This section is principally concerned with the usage of your model, using
266 the public API. Focus first on most common usage patterns, then go
267 into more advanced topics.
268 
269 Building New Module
270 ===================
271 
272 Include this subsection only if there are special build instructions or
273 platform limitations.
274 
275 Helpers
276 =======
277 
278 What helper API will users typically use? Describe it here.
279 
280 Attributes
281 ==========
282 
283 What classes hold attributes, and what are the key ones worth mentioning?
284 
285 Output
286 ======
287 
288 What kind of data does the model generate? What are the key trace
289 sources? What kind of logging output can be enabled?
290 
291 Advanced Usage
292 ==============
293 
294 Go into further details (such as using the API outside of the helpers)
295 in additional sections, as needed.
296 
297 Examples
298 ========
299 
300 What examples using this new code are available? Describe them here.
301 
302 Troubleshooting
303 ===============
304 
305 Add any tips for avoiding pitfalls, etc.
306 
307 Validation
308 **********
309 
310 Describe how the model has been tested/validated. What tests run in the
311 test suite? How much API and code is covered by the tests? Again,
312 references to outside published work may help here.
313 '''
314 
315 
316 def main(argv):
317  parser = OptionParser(usage=("Usage: %prog [options] modulename\n"
318  "Utility script to create a basic template for a new ns-3 module"))
319  (options, args) = parser.parse_args()
320  if len(args) != 1:
321  parser.print_help()
322  return 1
323 
324  modname = args[0].lower()
325  if False in [word.isalnum() for word in modname.split("-")]:
326  print("Module name should only contain alphanumeric characters and dashes", file=sys.stderr)
327  return 2
328  assert os.path.sep not in modname
329 
330  moduledir = os.path.join(os.path.dirname(__file__), modname)
331 
332  if os.path.exists(moduledir):
333  print("Module %r already exists" % (modname,), file=sys.stderr)
334  return 2
335 
336  print("Creating module %r, "
337  "run './waf configure' to include it in the build" % (modname,))
338 
339  os.mkdir(moduledir)
340  wscript = open(os.path.join(moduledir, "wscript"), "wt")
341  wscript.write(WSCRIPT_TEMPLATE % dict(MODULE=modname))
342  wscript.close()
343 
344 
345  #
346  # model
347  #
348  modeldir = os.path.join(moduledir, "model")
349  os.mkdir(modeldir)
350 
351  model_cc = open(os.path.join(moduledir, "model", "%s.cc" % modname), "wt")
352  model_cc.write(MODEL_CC_TEMPLATE % dict(MODULE=modname))
353  model_cc.close()
354 
355  model_h = open(os.path.join(moduledir, "model", "%s.h" % modname), "wt")
356  model_h.write(MODEL_H_TEMPLATE % dict(MODULE=modname, INCLUDE_GUARD="%s_H" % (modname.replace("-", "_").upper()),))
357  model_h.close()
358 
359 
360 
361  #
362  # test
363  #
364  testdir = os.path.join(moduledir, "test")
365  os.mkdir(testdir)
366  test_cc = open(os.path.join(moduledir, "test", "%s-test-suite.cc" % modname), "wt")
367  test_cc.write(TEST_CC_TEMPLATE % dict(MODULE=modname,
368  CAPITALIZED=''.join([word.capitalize() for word in modname.split('-')]),
369  COMPOUND=''.join([modname.split('-')[0]] + [word.capitalize() for word in modname.split('-')[1:]]),
370  ))
371  test_cc.close()
372 
373 
374 
375  #
376  # helper
377  #
378  helperdir = os.path.join(moduledir, "helper")
379  os.mkdir(helperdir)
380 
381  helper_cc = open(os.path.join(moduledir, "helper", "%s-helper.cc" % modname), "wt")
382  helper_cc.write(HELPER_CC_TEMPLATE % dict(MODULE=modname))
383  helper_cc.close()
384 
385  helper_h = open(os.path.join(moduledir, "helper", "%s-helper.h" % modname), "wt")
386  helper_h.write(HELPER_H_TEMPLATE % dict(MODULE=modname, INCLUDE_GUARD="%s_HELPER_H" % (modname.replace("-", "_").upper()),))
387  helper_h.close()
388 
389  #
390  # examples
391  #
392  examplesdir = os.path.join(moduledir, "examples")
393  os.mkdir(examplesdir)
394 
395  examples_wscript = open(os.path.join(examplesdir, "wscript"), "wt")
396  examples_wscript.write(EXAMPLES_WSCRIPT_TEMPLATE % dict(MODULE=modname))
397  examples_wscript.close()
398 
399  example_cc = open(os.path.join(moduledir, "examples", "%s-example.cc" % modname), "wt")
400  example_cc.write(EXAMPLE_CC_TEMPLATE % dict(MODULE=modname))
401  example_cc.close()
402 
403  #
404  # doc
405  #
406  docdir = os.path.join(moduledir, "doc")
407  os.mkdir(docdir)
408 
409  doc_rst = open(os.path.join(moduledir, "doc", "%s.rst" % modname), "wt")
410  doc_rst.write(DOC_RST_TEMPLATE % dict(MODULE=modname))
411  doc_rst.close()
412 
413 
414  return 0
415 
416 if __name__ == '__main__':
417  sys.exit(main(sys.argv))