doc: Add CommandLine::Usage to the doxygen for every example
This commit is contained in:
@@ -81,6 +81,7 @@ transmitted.</li>
|
||||
<li>The internal TCP API for <b>TcpCongestionOps</b> has been extended to support the <b>CongControl</b> method to allow for delivery rate estimation feedback to the congestion control mechanism.</li>
|
||||
<li>Functions <b>LteEnbPhy::ReceiveUlHarqFeedback</b> and <b>LteUePhy::ReceiveLteDlHarqFeedback</b> are renamed to <b>LteEnbPhy::ReportUlHarqFeedback</b> and <b>LteUePhy::EnqueueDlHarqFeedback</b>, respectively to avoid confusion about their functionality. <b>LteHelper</b> is updated accordingly.</li>
|
||||
<li>Now on, instead of <b>uint8_t</b>, <b>uint16_t</b> would be used to store a bandwidth value in LTE.</li>
|
||||
<li>The preferred way to declare instances of <b>CommandLine</b> is now through a macro: <b>COMMANDLINE (cmd)</b>. This enables us to add the <b>CommandLine::Usage()</b> message to the Doxygen for the program.</li>
|
||||
</ul>
|
||||
<h2>Changes to build system:</h2>
|
||||
<ul>
|
||||
|
||||
@@ -28,6 +28,7 @@ New user-visible features
|
||||
- (propagation) 3GPP TR 38.901 pathloss and channel condition models added
|
||||
- (spectrum) Addition three-gpp-channel-model (part of Integration of the 3GPP TR 38.901 fast fading model)
|
||||
- (antenna) Addition of three-gpp-antenna-array-model (part of Integration of the 3GPP TR 38.901 fast fading model)
|
||||
- (core) CommandLine can now add the Usage message to the Doxygen for the program; see CommandLine for details.
|
||||
|
||||
Bugs fixed
|
||||
----------
|
||||
|
||||
1
doc/.gitignore
vendored
1
doc/.gitignore
vendored
@@ -5,6 +5,7 @@
|
||||
latex/
|
||||
ns3-object.txt
|
||||
introspected-doxygen.h
|
||||
introspected-command-line.h
|
||||
doxygen.docset.conf
|
||||
doxygen.log
|
||||
doxygen.warnings.log
|
||||
|
||||
@@ -18,12 +18,6 @@
|
||||
* Authors: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
|
||||
#include <algorithm> // for transform
|
||||
#include <cctype> // for tolower
|
||||
#include <cstdlib> // for exit
|
||||
#include <iomanip> // for setw, boolalpha
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
|
||||
#include "command-line.h"
|
||||
#include "des-metrics.h"
|
||||
@@ -34,6 +28,14 @@
|
||||
#include "type-id.h"
|
||||
#include "string.h"
|
||||
|
||||
#include <algorithm> // transform
|
||||
#include <cctype> // tolower
|
||||
#include <cstdlib> // exit, getenv
|
||||
#include <cstring> // strlen
|
||||
#include <iomanip> // setw, boolalpha
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
|
||||
|
||||
/**
|
||||
* \file
|
||||
@@ -47,10 +49,22 @@ NS_LOG_COMPONENT_DEFINE ("CommandLine");
|
||||
|
||||
CommandLine::CommandLine ()
|
||||
: m_NNonOptions (0),
|
||||
m_nonOptionCount (0)
|
||||
m_nonOptionCount (0),
|
||||
m_usage (),
|
||||
m_shortName ()
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
}
|
||||
CommandLine::CommandLine (const std::string filename)
|
||||
: m_NNonOptions (0),
|
||||
m_nonOptionCount (0),
|
||||
m_usage ()
|
||||
{
|
||||
NS_LOG_FUNCTION (this << filename);
|
||||
std::string basename = SystemPath::Split (filename).back ();
|
||||
m_shortName = basename.substr (0, basename.rfind (".cc"));
|
||||
}
|
||||
|
||||
CommandLine::CommandLine (const CommandLine &cmd)
|
||||
{
|
||||
Copy (cmd);
|
||||
@@ -76,8 +90,9 @@ CommandLine::Copy (const CommandLine &cmd)
|
||||
std::copy (cmd.m_nonOptions.begin (), cmd.m_nonOptions.end (), m_nonOptions.end ());
|
||||
|
||||
m_NNonOptions = cmd.m_NNonOptions;
|
||||
m_usage = cmd.m_usage;
|
||||
m_name = cmd.m_name;
|
||||
m_nonOptionCount = 0;
|
||||
m_usage = cmd.m_usage;
|
||||
m_shortName = cmd.m_shortName;
|
||||
}
|
||||
void
|
||||
CommandLine::Clear (void)
|
||||
@@ -95,8 +110,8 @@ CommandLine::Clear (void)
|
||||
m_options.clear ();
|
||||
m_nonOptions.clear ();
|
||||
m_NNonOptions = 0;
|
||||
m_usage = "";
|
||||
m_name = "";
|
||||
m_usage = "";
|
||||
m_shortName = "";
|
||||
}
|
||||
|
||||
void
|
||||
@@ -108,7 +123,7 @@ CommandLine::Usage (const std::string usage)
|
||||
std::string
|
||||
CommandLine::GetName () const
|
||||
{
|
||||
return m_name;
|
||||
return m_shortName;
|
||||
}
|
||||
|
||||
CommandLine::Item::~Item ()
|
||||
@@ -121,12 +136,12 @@ CommandLine::Parse (std::vector<std::string> args)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << args.size () << args);
|
||||
|
||||
PrintDoxygenUsage ();
|
||||
|
||||
m_nonOptionCount = 0;
|
||||
m_name = "";
|
||||
|
||||
if (args.size () > 0)
|
||||
{
|
||||
m_name = SystemPath::Split (args[0]).back ();
|
||||
args.erase (args.begin ()); // discard the program name
|
||||
|
||||
for (auto param : args)
|
||||
@@ -218,6 +233,7 @@ CommandLine::HandleNonOption (const std::string &value)
|
||||
std::cerr << "Invalid non-option argument value "
|
||||
<< value << " for " << i->m_name
|
||||
<< std::endl;
|
||||
PrintHelp (std::cerr);
|
||||
std::exit (1);
|
||||
}
|
||||
++m_nonOptionCount;
|
||||
@@ -242,7 +258,7 @@ CommandLine::PrintHelp (std::ostream &os) const
|
||||
// Hack to show just the declared non-options
|
||||
Items nonOptions (m_nonOptions.begin (),
|
||||
m_nonOptions.begin () + m_NNonOptions);
|
||||
os << m_name
|
||||
os << m_shortName
|
||||
<< (m_options.size () ? " [Program Options]" : "")
|
||||
<< (nonOptions.size () ? " [Program Arguments]" : "")
|
||||
<< " [General Arguments]"
|
||||
@@ -316,6 +332,98 @@ CommandLine::PrintHelp (std::ostream &os) const
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
#include <unistd.h> // getcwd
|
||||
|
||||
void
|
||||
CommandLine::PrintDoxygenUsage (void) const
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
|
||||
{
|
||||
char buf[1024];
|
||||
std::string cwd= getcwd (buf, 1024);
|
||||
}
|
||||
|
||||
const char * envVar = std::getenv ("NS_COMMANDLINE_INTROSPECTION");
|
||||
if (envVar == 0 || std::strlen (envVar) == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_shortName.size () == 0)
|
||||
{
|
||||
NS_FATAL_ERROR ("No file name on example-to-run; forgot to use COMMANDLINE (var)?");
|
||||
return;
|
||||
}
|
||||
|
||||
// Hack to show just the declared non-options
|
||||
Items nonOptions (m_nonOptions.begin (),
|
||||
m_nonOptions.begin () + m_NNonOptions);
|
||||
|
||||
std::string outf = SystemPath::Append (std::string (envVar), m_shortName + ".command-line");
|
||||
|
||||
NS_LOG_INFO ("Writing CommandLine doxy to " << outf);
|
||||
|
||||
std::fstream os (outf, std::fstream::out);
|
||||
|
||||
|
||||
os << "/**\n \\file " << m_shortName << ".cc\n"
|
||||
<< "<h3>Usage</h3>\n"
|
||||
<< "<code>$ ./waf --run \"" << m_shortName
|
||||
<< (m_options.size () ? " [Program Options]" : "")
|
||||
<< (nonOptions.size () ? " [Program Arguments]" : "")
|
||||
<< "\"</code>\n";
|
||||
|
||||
if (m_usage.length ())
|
||||
{
|
||||
os << m_usage << std::endl;
|
||||
}
|
||||
|
||||
if (!m_options.empty ())
|
||||
{
|
||||
os << std::endl;
|
||||
os << "<h3>Program Options</h3>\n"
|
||||
<< "<dl>\n";
|
||||
for (auto i : m_options)
|
||||
{
|
||||
os << " <dt>\\c --" << i->m_name << "</dt>\n"
|
||||
<< " <dd>" << i->m_help;
|
||||
|
||||
if ( i->HasDefault ())
|
||||
{
|
||||
os << " [" << i->GetDefault () << "]";
|
||||
}
|
||||
os << "</dd>\n";
|
||||
}
|
||||
os << "</dl>\n";
|
||||
}
|
||||
|
||||
if (!nonOptions.empty ())
|
||||
{
|
||||
os << std::endl;
|
||||
os << "<h3>Program Arguments</h3>\n"
|
||||
<< "<dl>\n";
|
||||
for (auto i : nonOptions)
|
||||
{
|
||||
os << " <dt> \\c " << i->m_name << "</dt>\n"
|
||||
<< " <dd>" << i->m_help;
|
||||
|
||||
if ( i->HasDefault ())
|
||||
{
|
||||
os << " [" << i->GetDefault () << "]";
|
||||
}
|
||||
os << "</dd>\n";
|
||||
}
|
||||
os << "</dl>\n";
|
||||
}
|
||||
|
||||
os << "*/" << std::endl;
|
||||
|
||||
// All done, don't need to actually run the example
|
||||
os.close ();
|
||||
std::exit (0);
|
||||
}
|
||||
|
||||
void
|
||||
CommandLine::PrintGlobals (std::ostream &os) const
|
||||
{
|
||||
@@ -514,6 +622,7 @@ CommandLine::HandleArgument (const std::string &name, const std::string &value)
|
||||
{
|
||||
std::cerr << "Invalid argument value: "
|
||||
<< name << "=" << value << std::endl;
|
||||
PrintHelp (std::cerr);
|
||||
std::exit (1);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -45,6 +45,17 @@ namespace ns3 {
|
||||
*
|
||||
* The main entry point is CommandLine
|
||||
*/
|
||||
|
||||
/**
|
||||
* \ingroup commandline
|
||||
* \brief Declare a CommandLine instance.
|
||||
*
|
||||
* This form is preferred since it supports creating Doxygen
|
||||
* documentation for programs from the CommandLine configuration.
|
||||
*/
|
||||
#define COMMANDLINE(var) \
|
||||
CommandLine var ( __FILE__ )
|
||||
|
||||
/**
|
||||
* \ingroup commandline
|
||||
* \brief Parse command-line arguments
|
||||
@@ -105,7 +116,6 @@ namespace ns3 {
|
||||
* Suggested best practice is for scripts to report the values of all items
|
||||
* settable through CommandLine, as done by the example below.
|
||||
*
|
||||
*
|
||||
* CommandLine can set the initial value of every attribute in the system
|
||||
* with the \c --TypeIdName::AttributeName=value syntax, for example
|
||||
* \verbatim
|
||||
@@ -133,7 +143,7 @@ namespace ns3 {
|
||||
* bool boolArg = false;
|
||||
* std::string strArg = "strArg default";
|
||||
*
|
||||
* CommandLine cmd;
|
||||
* COMMANDLINE (cmd);
|
||||
* cmd.Usage ("CommandLine example program.\n"
|
||||
* "\n"
|
||||
* "This little program demonstrates how to use CommandLine.");
|
||||
@@ -194,7 +204,7 @@ namespace ns3 {
|
||||
* int value1;
|
||||
* int value2;
|
||||
*
|
||||
* CommandLine cmd;
|
||||
* COMMANDLINE (cmd);
|
||||
* cmd.Usage ("...");
|
||||
* cmd.AddValue ("value1", "first value", value1);
|
||||
* cmd.AddValue ("value2", "second value", value1);
|
||||
@@ -208,12 +218,33 @@ namespace ns3 {
|
||||
* exit (-1);
|
||||
* }
|
||||
* \endcode
|
||||
*
|
||||
* Finally, note that for examples which will be run by \c test.py
|
||||
* the preferred declaration of a CommandLine instance is
|
||||
* to use the \c COMMANDLINE macro to declare the instance name:
|
||||
*
|
||||
* \code
|
||||
* COMMANDLINE (cmd);
|
||||
* \endcode
|
||||
* This will ensure that the program usage and arguments can be added to
|
||||
* the Doxygen documentation automatically.
|
||||
*/
|
||||
class CommandLine
|
||||
{
|
||||
public:
|
||||
/** Constructor */
|
||||
CommandLine ();
|
||||
CommandLine (void);
|
||||
/**
|
||||
* Construct and register the source file name.
|
||||
* This would typically be called by using the \c COMMANDLINE macro:
|
||||
* COMMANDLINE (cmd);
|
||||
*
|
||||
* This is just syntactic sugar for
|
||||
* COMMANDLINE cmd (__FILE__);
|
||||
* This form is required to generate Doxygen documentation of the
|
||||
* arguments and options.
|
||||
*/
|
||||
CommandLine (const std::string filename);
|
||||
/**
|
||||
* Copy constructor
|
||||
*
|
||||
@@ -359,7 +390,7 @@ public:
|
||||
*
|
||||
* Alternatively, an overloaded operator << can be used:
|
||||
* \code
|
||||
* CommandLine cmd;
|
||||
* COMMANDLINE (cmd);
|
||||
* cmd.Parse (argc, argv);
|
||||
* ...
|
||||
*
|
||||
@@ -520,6 +551,11 @@ private:
|
||||
void Copy (const CommandLine &cmd);
|
||||
/** Remove all arguments, Usage(), name */
|
||||
void Clear (void);
|
||||
/**
|
||||
* Append usage message in Doxygen format to the file indicated
|
||||
* by the NS_COMMANDLINE_INTROSPECTION environment variable.
|
||||
*/
|
||||
void PrintDoxygenUsage (void) const;
|
||||
|
||||
typedef std::vector<Item *> Items; /**< Argument list container */
|
||||
Items m_options; /**< The list of option arguments */
|
||||
@@ -527,7 +563,7 @@ private:
|
||||
std::size_t m_NNonOptions; /**< The expected number of non-option arguments */
|
||||
std::size_t m_nonOptionCount; /**< The number of actual non-option arguments seen so far. */
|
||||
std::string m_usage; /**< The Usage string */
|
||||
std::string m_name; /**< The program name */
|
||||
std::string m_shortName; /**< The source file name (without `.cc`), as would be given to `waf --run` */
|
||||
|
||||
}; // class CommandLine
|
||||
|
||||
@@ -669,7 +705,7 @@ CommandLineHelper::UserItemParse (const std::string value, T & val)
|
||||
*
|
||||
* Example usage:
|
||||
* \code
|
||||
* CommandLine cmd;
|
||||
* COMMANDLINE (cmd);
|
||||
* cmd.Parse (argc, argv);
|
||||
* ...
|
||||
*
|
||||
|
||||
34
wscript
34
wscript
@@ -11,6 +11,8 @@ import re
|
||||
import shlex
|
||||
import subprocess
|
||||
import textwrap
|
||||
import fileinput
|
||||
import glob
|
||||
|
||||
from utils import read_config_file
|
||||
|
||||
@@ -1259,6 +1261,38 @@ def _print_introspected_doxygen(bld):
|
||||
raise SystemExit(1)
|
||||
text_out.close()
|
||||
|
||||
# Gather the CommandLine doxy
|
||||
# test.py appears not to create or keep the output directory
|
||||
# if no real tests are run, so we just stuff all the
|
||||
# .command-line output files into testpy-output/
|
||||
# NS_COMMANDLINE_INTROSPECTION=".." test.py --nowaf --constrain=example
|
||||
Logs.info("Running CommandLine introspection")
|
||||
proc_env['NS_COMMANDLINE_INTROSPECTION'] = '..'
|
||||
subprocess.run(["test.py", "--nowaf", "--constrain=example"],
|
||||
env=proc_env, stdout=subprocess.DEVNULL)
|
||||
|
||||
doxygen_out = os.path.join('doc', 'introspected-command-line.h')
|
||||
try:
|
||||
os.remove(doxygen_out)
|
||||
except OSError as e:
|
||||
pass
|
||||
|
||||
with open(doxygen_out, 'w') as out_file:
|
||||
lines="""
|
||||
/* This file is automatically generated by
|
||||
CommandLine::PrintDoxygenUsage() from the CommandLine configuration
|
||||
in various example programs. Do not edit this file! Edit the
|
||||
CommandLine configuration in those files instead.
|
||||
*/\n
|
||||
"""
|
||||
out_file.write(lines)
|
||||
out_file.close()
|
||||
|
||||
with open(doxygen_out,'a') as outfile:
|
||||
for in_file in glob.glob('testpy-output/*.command-line'):
|
||||
with open(in_file,'r') as infile:
|
||||
outfile.write(infile.read())
|
||||
|
||||
def _doxygen(bld, skip_pid=False):
|
||||
env = wutils.bld.env
|
||||
proc_env = wutils.get_proc_env()
|
||||
|
||||
Reference in New Issue
Block a user