diff --git a/.clang-format b/.clang-format index 1ee1d06ef..477d39c7e 100644 --- a/.clang-format +++ b/.clang-format @@ -26,4 +26,4 @@ PackConstructorInitializers: Never PointerAlignment: Left QualifierAlignment: Left SeparateDefinitionBlocks: Always -Standard: "c++17" +Standard: "c++20" diff --git a/.clang-tidy b/.clang-tidy index 924c8086e..eebfa02f0 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -47,7 +47,6 @@ Checks: > readability-static-accessed-through-instance, readability-static-definition-in-anonymous-namespace, readability-string-compare, - readability-uppercase-literal-suffix, CheckOptions: - key: performance-unnecessary-copy-initialization.AllowedTypes @@ -55,6 +54,9 @@ CheckOptions: - key: readability-simplify-boolean-expr.SimplifyDeMorgan value: false +ExtraArgsBefore: + - -Wno-unknown-warning-option + FormatStyle: "file" HeaderFilterRegex: ".*(ns|NS).*/(contrib|examples|src|scratch|utils)/*/.*h" UseColor: true diff --git a/.editorconfig b/.editorconfig index 4b279abb8..7c4345e3e 100644 --- a/.editorconfig +++ b/.editorconfig @@ -10,10 +10,14 @@ root = true [*] -end_of_line = lf # Unix-style newlines -charset = utf-8 # All files are in UTF-8 -insert_final_newline = true # All files end with a newline -trim_trailing_whitespace = true # No trailing whitespaces +# Unix-style newlines +end_of_line = lf +# All files are in UTF-8 +charset = utf-8 +# All files end with a newline +insert_final_newline = true +# No trailing whitespaces +trim_trailing_whitespace = true [Makefile] indent_style = tab diff --git a/.github/workflows/per_commit.yml b/.github/workflows/per_commit.yml index 44757a75e..1f298afd2 100644 --- a/.github/workflows/per_commit.yml +++ b/.github/workflows/per_commit.yml @@ -50,7 +50,7 @@ jobs: CodeQL: runs-on: ubuntu-latest needs: Ubuntu - if: needs.Ubuntu.outputs.cache_misses != '0' + if: ${{ (needs.Ubuntu.outputs.cache_misses != '0') && (github.repository == 'nsnam/ns-3-dev-git') }} strategy: fail-fast: false steps: diff --git a/AUTHORS b/AUTHORS index eb103c65e..9214478b3 100644 --- a/AUTHORS +++ b/AUTHORS @@ -27,10 +27,12 @@ Ramon Bauza (monbauza@gmail.com) Pedro Bellotti (pedro177@gmail.com) Mehdi Benamor (mehdi.benamor@telecom-bretagne.eu) Apoorva Bhargava (apoorvabhargava13@gmail.com) -Avakash Bhat(avakash261@gmail.com) +Avakash Bhat (avakash261@gmail.com) +Kavya Bhat (kavyabhat@gmail.com) Raj Bhattacharjea (raj.b@gatech.edu) Mathew Bielejeski (bielejeski1@llnl.gov) Timo Bingmann (timo.bingmann@student.kit.edu) +Doug Blough (doug.blough@gatech.edu) Julien Boite (juboite@gmail.com) Biljana Bojovic (bbojovic@cttc.es) Elena Borovkova (borokovaes@iitp.ru) @@ -42,6 +44,7 @@ Dan Broyles (muxman@sbcglobal.net) Jonathan Brugge (j.d.brugge@student.utwente.nl) Junling Bu (linlinjavaer@gmail.com) Elena Buchatskaia (borovkovaes@iitp.ru) +Alessio Bugetti (alessiobugetti98@gmail.com) Nuno Cardoso (nunopcardoso@gmail.com) Gustavo Carneiro (gjc@inescporto.pt, gjcarneiro@gmail.com) Scott Carpenter (scarpen@ncsu.edu) @@ -160,6 +163,7 @@ Hossam Khader (hossamkhader@gmail.com) Alexander Krotov (ilabdsf@yandex.ru) Deepak Kumaraswamy (deepakkavoor99@gmail.com) Mathieu Lacage (mathieu.lacage@inria.fr) +Andrea Lacava (thecave003@gmail.com) Sandra Lagen (sandra.lagen@cttc.es) Emmanuelle Laprise (emmmanuelle.laprise@bluekazoo.ca) Harsh Lara (harshapplefan@gmail.com) @@ -181,6 +185,7 @@ Federico Maguolo (maguolof@dei.unipd.it) Antti Makela (zarhan@cc.hut.fi) Francesco Malandrino (francesco.malandrino@gmail.com) Rubén Martínez (rmartinez@deic.uab.cat) +Chaz Maschman Ryan Mast (mast9@llnl.gov) Fabian Mauchle (f1mauchl@hsr.ch) Mauriyin (haoyin@uw.edu) @@ -188,6 +193,7 @@ Andrey Mazo (mazo@iitp.ru) Jonathan McCrohan (jmccroha@tcd.ie) Andrew McGregor (andrewmcgr@gmail.com) Miralem Mehic (miralemmehic@gmail.com) +Levente Mészáros (levy@omnetpp.org) Vedran Miletić (rivanvx@gmail.com) Saswat Mishra (clicksaswat@gmail.com) Jens Mittag (jens.mittag@kit.edu) @@ -242,6 +248,7 @@ Ovidiu Poncea (ovidiu.poncea@cs.pub.ro) Anna Poon (poon2@llnl.gov) Gauri Prasad Vikas Pushkar (vikaskupushkar@gmail.com) +Martin Quinson (mquinson@debian.org) Philipp Raich (philipp.raich@tuwien.ac.at) Alberto Gallegos Ramonet (alramonet@is.tokushima-u.ac.jp) Manoj Kumar Rana (manoj24.rana@gmail.com) @@ -327,6 +334,7 @@ Florian Westphal (fw@strlen.de) He Wu (mdzz@u.washington.edu) Xiuchao Wu (xiuchao@amazon.com) Aron Wussler (aron@wussler.it) +Heran Yang (heran55@126.com) Yoshihiko Yazawa (yoshiyaz@gmail.com) Menglei Zhang (menglei@nyu.edu) Theodore Zhang (harryzwh@gmail.com) diff --git a/CHANGES.md b/CHANGES.md index 6b7dcd88b..dd6572e6e 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -13,6 +13,66 @@ Note that users who upgrade the simulator across versions, or who work directly This file is a best-effort approach to solving this issue; we will do our best but can guarantee that there will be things that fall through the cracks, unfortunately. If you, as a user, can suggest improvements to this file based on your experience, please contribute a patch or drop us a note on ns-developers mailing list. +Changes from ns-3.40 to ns-3.41 +------------------------------- + +### New API + +* (core) Added `BernoulliRandomVariable` class implementing the bernoulli random variable, and `BinomialRandomVariable` class implementing the binomial random variable. +* (core) Added wrapper around `UniformRandomVariable` to meet the C++11 requirements of UniformRandomBitGenerator. +* (core) Added method to `GetStopEvent()` from `Simulator` +* (internet) It is now possible to set the TOS field for IPv4 ICMP Echo Requests/Responses, via a new `Tos` attribute. +* (spectrum) `SpectrumSignalParameters` is extended to include two new members called: `spectrumChannelMatrix` and `precodingMatrix` which are the key information needed to support MIMO simulations. +* (spectrum) `SpectrumChannel::AssignStreams()` is added, to allow random variable stream assignment for all propagation loss and delay models added to the channel. +* (wifi) Added new attribute `ChannelAccessManager:GenerateBackoffIfTxopWithoutTx` to invoke the backoff procedure when an AC gains the right to start a TXOP but it does not transmit any frame, provided that the queue is not actually empty. No transmission may occur,e.g., due to constraints associated with EMLSR operations. This possibility is specified by the current draft revision of the IEEE 802.11 standard. + +### Changes to existing API + +* (antenna) `UniformPlannarArray` has new attributes `NumVerticalPorts`, `NumHorizontalPorts`, and `IsDualPolarized`. +* (antenna) `GetNumberOfElements` is renamed to `GetNumElems` for the sake of simplifying the long lines of code that use complex mathematical expressions. +* (core) The EnumValue class now also supports enum class in addition to plain enums. As a result of this change, attributes that wrap enums must update the syntax for the `MakeEnumAccessor` method call. Where you once were able to write, for example (from attribute-test-suite.cc): + + ```cpp + MakeEnumAccessor(&AttributeObjectTest::m_enum), + ``` + + you must now write it with a template parameter such as: + + ```cpp + MakeEnumAccessor(&AttributeObjectTest::m_enum), + ``` +* (internet) Deprecated `Ipv4::WeakEsModel` and `Ipv4::GetWeakEsModel()`, `Ipv4::SetWeakEsModel(bool)` methods. Moved `Ipv6L3Protocol::StrongEndSystemModel` to `Ipv6::StrongEndSystemModel` and added `Ipv4::StrongEndSystemModel` with corresponding `GetStrongEndSystemModel()` and `SetStrongEndSystemModel(bool)` methods to improve end system model configuration options. +* (lr-wpan) Change the CapabilityField parameter in `LrWpanMac::MlmeAssociateRequest` and `LrWpanMac::MlmeAssociateIndication` to a standard bitmap. +* (lr-wpan) Change the MAC SuperframeField usage to a standard bitmap, this change impact parameters in the `BeaconPayloadHeader`. +* (lr-wpan) Create a new abstract class that defines the form of any Lr-wpan MAC layers (`LrWpanMacBase`). +* (lr-wpan) Add the capability to see the enum values of the MAC transition states in log prints for easier debugging. +* (lr-wpan) Group MAC status enumerations into a single `LrWpanMacStatus` enumeration in `lr-wpan-mac-base.h.` +* The spelling of the following files, classes, functions, constants, defines and enumerated values was corrected; this will affect existing users who were using them with the misspelling. + * (lte) Struct member `fdbetsFlowPerf_t::lastTtiBytesTrasmitted` in file `fdbet-ff-mac-scheduler.h` was renamed `fdbetsFlowPerf_t::lastTtiBytesTransmitted`. + * (lte) Struct member `tdbetsFlowPerf_t::lastTtiBytesTrasmitted` in file `tdbet-ff-mac-scheduler.h` was renamed `fdbetsFlowPerf_t::lastTtiBytesTransmitted`. + * (lte) Struct member `pfsFlowPerf_t::lastTtiBytesTrasmitted` in file `pf-ff-mac-scheduler.h` was renamed `fdbetsFlowPerf_t::lastTtiBytesTransmitted`. +* (sixlowpan) Remove `ForceEtherType` and `EtherType` attributes, and use RFC 7973 EtherType for interfaces supporting an EtherType. +* (spectrum) `PhasedArraySpectrumPropagationLossModel::CalcRxPowerSpectralDensity` return type is changed from `Ptr` to `Ptr` to support MIMO, because when multiple transmit and receive antenna ports are present, it is not enough to have a single PSD (represented by `Ptr`) but also the 3D channel matrix is needed per receive and transmit antenna port. Notice that `CalcRxPowerSpectralDensity` is typically called from within `MultiModelSpectrumChannel`, but if some external ns-3 module is calling directly this function, it can still access to its original return value through `Ptr` which contains `Ptr`. +* (wifi) The `HeConfiguration::MpduBufferSize` attribute is now obsolete. Use the `WifiMac::MpduBufferSize` attribute instead. +* (wifi) The `LinkSetupCanceled` trace source of `StaWifiMac` has been obsoleted because disassociation does not occur at link level for non-AP MLDs. +* (wifi) The default value for `WifiRemoteStationManager::RtsCtsThreshold` has been increased from 65535 to 4692480. +* (wifi) `SpectrumWifiHelper::SpectrumChannelSwitched()` is now static + +### Changes to build system + +* In preparation to enable C++20, the following actions have been taken due to compiler issues: + * Precompiled headers have been disabled in GCC versions >= 12.2. + * The `restrict` warning has been disabled in GCC versions 12.1-12.3.1. +* Raised minimum CMake version to 3.13. +* Raised minimum C++ version to C++20. +* Added guard rails for scratch targets missing or containing more than one `main` function. + +### Changed behavior +* (sixlowpan) Now uses RFC 7973 Ethertype by default +* (spectrum) SpectrumChannel objects and the loss/delay models attached are now automatically initialized (Object::Initialize) at time zero +* (tcp) TCP Cubic (the default congestion control in ns-3) now supports TCP-friendliness by default (see RFC 9438 Section 4.3), making the congestion window growth somewhat more aggressive. This follows the default Linux behavior. +* (wifi) Increase the duration of the timer started when waiting for an ADDBA_RESPONSE from 1ms to 5ms to better account for the time required by the recipient to access the medium and complete the frame exchange (which may involve protection with (MU-)RTS/CTS). + Changes from ns-3.39 to ns-3.40 ------------------------------- @@ -48,7 +108,7 @@ Changes from ns-3.38 to ns-3.39 ### New API -* (lr-wpan) Added support for orphan scans. Orphan scans can now be performed using the existing `LrWpanMac::MlmeScanRequest`; This orphan scan use the added orphan notification commands and coordinator realigment commands. Usage is shown in added `lr-wpan-orphan-scan.cc` example and in the `TestOrphanScan` included in `lr-wpan-mac-test.cc`. +* (lr-wpan) Added support for orphan scans. Orphan scans can now be performed using the existing `LrWpanMac::MlmeScanRequest`; This orphan scan use the added orphan notification commands and coordinator realignment commands. Usage is shown in added `lr-wpan-orphan-scan.cc` example and in the `TestOrphanScan` included in `lr-wpan-mac-test.cc`. * (network) Added `Mac64Address::ConvertToInt`. Converts a Mac64Address object to a uint64_t. * (network) Added `Mac16Address::ConvertToInt`. Converts a Mac16Address object to a uint16_t. * (network) Added `Mac16Address::Mac16Address(uint16t addr)` and `Mac16Address::Mac64Address(uint64t addr)` constructors. @@ -360,6 +420,7 @@ Changes from ns-3.33 to ns-3.34 * The **wifi BCC AWGN error rate tables** have been aligned with the ones provided by MATLAB and users may note a few dB difference when using BCC at high SNR and high MCS. * **`ThreeGppChannelModel` has been fixed**: cluster and sub-cluster angles could have been generated with inclination angles outside the inclination range `[0, pi]`, and have now been constrained to the correct range. * The **LTE RLC Acknowledged Mode (AM) transmit buffer** is now limited by default to a size of (`1024 * 10`) bytes. Configuration of unlimited behavior can still be made by passing the value of zero to the new attribute `MaxTxBufferSize`. +* A **non-AP MLD loses association** when receiving no beacon an any link link for an interval of duration equal to the maximum number of missed beacons times the interval between two consecutive Beacon frames. Changes from ns-3.32 to ns-3.33 ------------------------------- @@ -489,7 +550,7 @@ Changes from ns-3.30 to ns-3.31 * (as reported above) previously the `Config::Connect` and `Config::Set` families of functions would fail silently if the attribute or trace source didn't exist on the path given (typically due to spelling errors). Now those functions will throw a fatal error. If you need the old behavior use the new `...FailSafe ()` variants. * Attempting to deserialize an enum name which wasn't registered with `MakeEnumChecker` now causes a fatal error, rather failing silently. (This can be triggered by setting an enum Attribute from a StringValue.) * As a result of the above API changes in `MobilityBuildingInfo` and `BuildingsHelper` classes, a building aware pathloss models, e.g., `HybridBuildingsPropagationLossModel` is now able to accurately compute the pathloss for a node moving in and out of buildings in a simulation. See [issue 80](https://gitlab.com/nsnam/ns-3-dev/issues/80) for discussion. -* The implementation of the **Wi-Fi channel access** functions has been improved to make them more conformant to the IEEE 802.11-2016 standard. Concerning the DCF, the backoff procedure is no longer invoked when a packet is queued for transmission and the medium has not been idle for a DIFS, but it is invoked if the medium is busy or does not remain idle for a DIFS after the packet has been queued. Concerning the EDCAF, tranmissions are now correctly aligned at slot boundaries. +* The implementation of the **Wi-Fi channel access** functions has been improved to make them more conformant to the IEEE 802.11-2016 standard. Concerning the DCF, the backoff procedure is no longer invoked when a packet is queued for transmission and the medium has not been idle for a DIFS, but it is invoked if the medium is busy or does not remain idle for a DIFS after the packet has been queued. Concerning the EDCAF, transmissions are now correctly aligned at slot boundaries. * Various wifi physical layer behavior around channel occupancy calculation, phy state calculation, and handling different channel widths has been updated. Changes from ns-3.29 to ns-3.30 diff --git a/CMakeLists.txt b/CMakeLists.txt index 442cf883b..97656e0e8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ # ############################################################################## # Required CMake version # # ############################################################################## -cmake_minimum_required(VERSION 3.10..3.10) +cmake_minimum_required(VERSION 3.13..3.13) # ############################################################################## # Project name # @@ -12,8 +12,8 @@ file(STRINGS VERSION NS3_VER) # minimum compiler versions set(AppleClang_MinVersion 11.0.0) -set(Clang_MinVersion 6.0.0) -set(GNU_MinVersion 8.0.0) +set(Clang_MinVersion 10.0.0) +set(GNU_MinVersion 9.0.0) # common options option(NS3_ASSERT "Enable assert on failure" OFF) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 5e60a81c3..0dd5528ac 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -13,6 +13,60 @@ a [GitLab.com issue tracker](https://gitlab.com/nsnam/ns-3-dev/-/issues) number, and references prefixed by '!' refer to a [GitLab.com merge request](https://gitlab.com/nsnam/ns-3-dev/-/merge_requests) number. +Release 3.41 +------------ + +### Availability + +This release is available from: + + +### Supported platforms + +This release is intended to work on systems with the following minimal +requirements (Note: not all ns-3 features are available on all systems): + +- g++-9 or later, or LLVM/clang++-10 or later +- Python 3.6 or later +- CMake 3.13 or later +- (macOS only) Xcode 11 or later +- (Windows only) Msys2/MinGW64 toolchain or WSL2 + +Python API requires [Cppyy](https://cppyy.readthedocs.io/en/latest/installation.html) and works for Linux only. Specifically, avoid Cppyy version 3; stay with version 2.4.2 for this release. + +### New user-visible features + +- (antenna) !1337 - `UniformPlanarArray` is extended to support multiple horizontal and vertical antenna ports, and dual-polarized antennas. +- (core) !1364 - The `MakeEnumAccessor` was changed to support `enum class` types +- (core) !1802 - Added support for Bernoulli and Binomial random variables (`BernoulliRandomVariable`, `BinomialRandomVariable`) +- (internet) #1001 - TCP Cubic now supports Reno-friendly operation by default. +- (internet) !1817 - Resolved inconsistency in behavior regarding the Strong End System Model between IPv4 and IPv6. Attributes `Ipv6L3Protocol::StrongEndSystemModel` and `Ipv4::WeakEsModel` have been aligned to provide a consistent user experience and avoid confusion +- (lr-wpan) !1686 - Change CapabilityField to standard bitmap +- (lr-wpan) !1698 - Change SuperframeField to standard bitmap +- (lr-wpan) !1711 - Add `pCurrentPage` and `pCurrentChannel` attributes to MLME-GET.request primitive +- (lr-wpan) !1706 - Create MAC layer abstraction (decoupling, alternative MACs) via a new `LrWpanBase` class +- (lr-wpan) !1794 - Group MAC primitives status enumerations into a single enumeration +- (spectrum)!1337 - `ThreeGppSpectrumPropagationLossModel` and `ThreeGppChannelModel` are extended to support multi-port and dual-polarized antenna arrays which is a basis for enabling 3GPP MIMO simulations in ns-3. +- (wifi) - Added support for BlockAck buffer size of up to 1024 MPDUs (EHT STAs only) +- (wifi) - Aligned default RTS threshold to 802.11-2020 +- (wifi) - Added EHT support for Ideal rate manager + +### Bugs fixed + +- (lr-wpan) !1673 - Fixes PHY BUSY_RX -> RX_ON operation +- (lr-wpan) !1769 - `DoDispose` SIGSEGV and beacon fixes +- (network) !1746 - `PacketSocketClient` not scheduling `Send()` for packet bursts +- (network) !1793 - Fix string to MAC address parsing logic +- (tap-bridge) !1540 - Update examples to support modern Wi-Fi standards +- (tcp) !1788, !1825 - Fix several small issues with `examples/tcp/tcp-bbr-example.cc` and `examples/tcp/tcp-linux-reno.cc` +- (tcp) !1812 - Several small fixes to TCP retransmission logic were added, based on trace comparison with OMNeT++ +- (tcp) #1026 - TcpRateLinux (delivery rate estimation) had an incorrect update to the rate sample +- (visualizer) !1730 - Fix label positioning in PyViz +- (wifi) - Fix agreement not always properly torn down when Block Ack inactivity timeout is elapsed +- (wifi) - Stop A-MSDU aggregation when an A-MSDU is found in the queue +- (wifi) - ReportAmpduTxStatus called twice when sending explicit BAR upon missed BlockAck +- (wifi) - Fix regression causing BlockAckReq frames to be sent with data rates instead of control rates + Release 3.40 ------------ @@ -1264,7 +1318,7 @@ This release has been tested on the following platforms: - Bug 2587 - tcp: Avoid overflow in htcp.cc - Bug 2590 - traffic-control: Minor enhancements in red-queue-disc{.h, .cc} - Bug 2591 - wifi: 802.11e Block Ack cannot be enabled on HT/VHT stations -- Bug 2594 - wifi: vht-wifi-network very low throughtput at MCS 6, 160 MHz, SGI +- Bug 2594 - wifi: vht-wifi-network very low throughput at MCS 6, 160 MHz, SGI - Bug 2596 - network: EthernetTrailer::GetFcs() should be const - Bug 2601 - wifi: HT stations should use 40 MHz width if configured 80 or 160z - Bug 2604 - wifi: QosData frames separation with Block Ack enabled diff --git a/VERSION b/VERSION index a2b1f5109..91bf8e413 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.40 +3.41 diff --git a/bindings/python/ns__init__.py b/bindings/python/ns__init__.py index f0f3c5d20..fbd8179af 100644 --- a/bindings/python/ns__init__.py +++ b/bindings/python/ns__init__.py @@ -1,10 +1,10 @@ import builtins -from functools import lru_cache import glob import os.path +import re import sys import sysconfig -import re +from functools import lru_cache DEFAULT_INCLUDE_DIR = sysconfig.get_config_var("INCLUDEDIR") DEFAULT_LIB_DIR = sysconfig.get_config_var("LIBDIR") @@ -14,7 +14,7 @@ def find_ns3_lock() -> str: # Get the absolute path to this file path_to_this_init_file = os.path.dirname(os.path.abspath(__file__)) path_to_lock = path_to_this_init_file - lock_file = (".lock-ns3_%s_build" % sys.platform) + lock_file = ".lock-ns3_%s_build" % sys.platform # Move upwards until we reach the directory with the ns3 script prev_path = None @@ -32,15 +32,17 @@ def find_ns3_lock() -> str: return path_to_lock -SYSTEM_LIBRARY_DIRECTORIES = (DEFAULT_LIB_DIR, - os.path.dirname(DEFAULT_LIB_DIR), - "/usr/lib64", - "/usr/lib" - ) -DYNAMIC_LIBRARY_EXTENSIONS = {"linux": "so", - "win32": "dll", - "darwin": "dylib" - } +SYSTEM_LIBRARY_DIRECTORIES = ( + DEFAULT_LIB_DIR, + os.path.dirname(DEFAULT_LIB_DIR), + "/usr/lib64", + "/usr/lib", +) +DYNAMIC_LIBRARY_EXTENSIONS = { + "linux": "so", + "win32": "dll", + "darwin": "dylib", +} LIBRARY_EXTENSION = DYNAMIC_LIBRARY_EXTENSIONS[sys.platform] @@ -76,8 +78,9 @@ def _search_libraries() -> dict: library_search_paths += [os.path.dirname(library_search_paths[-1])] # Filter unique search paths and those that are not part of system directories - library_search_paths = list(filter(lambda x: x not in SYSTEM_LIBRARY_DIRECTORIES, - set(library_search_paths))) + library_search_paths = list( + filter(lambda x: x not in SYSTEM_LIBRARY_DIRECTORIES, set(library_search_paths)) + ) # Search for the core library in the search paths libraries = [] @@ -88,7 +91,9 @@ def _search_libraries() -> dict: # Search system library directories (too slow for recursive search) for search_path in SYSTEM_LIBRARY_DIRECTORIES: if os.path.exists(search_path): - libraries += glob.glob("%s/**/*.%s*" % (search_path, LIBRARY_EXTENSION), recursive=False) + libraries += glob.glob( + "%s/**/*.%s*" % (search_path, LIBRARY_EXTENSION), recursive=False + ) libraries += glob.glob("%s/*.%s*" % (search_path, LIBRARY_EXTENSION), recursive=False) del search_path, library_search_paths @@ -106,7 +111,7 @@ def _search_libraries() -> dict: library_map[library_infix].add(library) # Replace sets with lists - for (key, values) in library_map.items(): + for key, values in library_map.items(): library_map[key] = list(values) return library_map @@ -128,7 +133,7 @@ LIBRARY_AND_DEFINES = { "libxml2": ["HAVE_LIBXML2"], "libsqlite3": ["HAVE_SQLITE3"], "openflow": ["NS3_OPENFLOW", "ENABLE_OPENFLOW"], - "click": ["NS3_CLICK"] + "click": ["NS3_CLICK"], } @@ -137,11 +142,11 @@ def add_library_defines(library_name: str): defines = "" if len(has_defines): for define in LIBRARY_AND_DEFINES[has_defines[0]]: - defines += (f""" + defines += f""" #ifndef {define} #define {define} 1 #endif - """) + """ return defines @@ -156,10 +161,11 @@ def extract_linked_libraries(library_name: str, prefix: str) -> tuple: # First discover which 3rd-party libraries are used by the current module try: with open(os.path.abspath(library_path), "rb") as f: - linked_libs = re.findall(b"\x00(lib.*?.%b)" % LIBRARY_EXTENSION.encode("utf-8"), f.read()) + linked_libs = re.findall( + b"\x00(lib.*?.%b)" % LIBRARY_EXTENSION.encode("utf-8"), f.read() + ) except Exception as e: - print("Failed to extract libraries used by {library} with exception:{exception}" - .format(library=library_path, exception=e)) + print(f"Failed to extract libraries used by {library_path} with exception:{e}") exit(-1) return library_path, lib, list(map(lambda x: x.decode("utf-8"), linked_libs)) @@ -182,8 +188,8 @@ def extract_library_include_dirs(library_name: str, prefix: str) -> tuple: # Raise error in case the library can't be found if len(linked_library_path) == 0: raise Exception( - "Failed to find {library}. Make sure its library directory is in LD_LIBRARY_PATH.".format( - library=linked_library)) + f"Failed to find {linked_library}. Make sure its library directory is in LD_LIBRARY_PATH." + ) # Get path with the shortest length linked_library_path = sorted(linked_library_path, key=lambda x: len(x))[0] @@ -201,7 +207,9 @@ def extract_library_include_dirs(library_name: str, prefix: str) -> tuple: linked_libs_include_dirs.add(system_include_dir) # If system_include_dir/library_name exists, we add it too - linked_library_name = linked_library.replace("lib", "").replace("." + LIBRARY_EXTENSION, "") + linked_library_name = linked_library.replace("lib", "").replace( + "." + LIBRARY_EXTENSION, "" + ) if os.path.exists(os.path.join(system_include_dir, linked_library_name)): linked_libs_include_dirs.add(os.path.join(system_include_dir, linked_library_name)) @@ -232,19 +240,26 @@ def find_ns3_from_lock_file(lock_file: str) -> (str, list, str): suffix = "-" + values["BUILD_PROFILE"] if values["BUILD_PROFILE"] != "release" else "" modules = [module.replace("ns3-", "") for module in values["NS3_ENABLED_MODULES"]] prefix = values["out_dir"] - libraries = {os.path.splitext(os.path.basename(x))[0]: x for x in os.listdir(os.path.join(prefix, "lib"))} + libraries = { + os.path.splitext(os.path.basename(x))[0]: x for x in os.listdir(os.path.join(prefix, "lib")) + } version = values["VERSION"] # Filter out test libraries and incorrect versions - def filter_in_matching_ns3_libraries(libraries_to_filter: dict, - modules_to_filter: list, - version: str, - suffix: str) -> dict: + def filter_in_matching_ns3_libraries( + libraries_to_filter: dict, + modules_to_filter: list, + version: str, + suffix: str, + ) -> dict: suffix = [suffix[1:]] if len(suffix) > 1 else [] filtered_in_modules = [] for module in modules_to_filter: - filtered_in_modules += list(filter(lambda x: "-".join([version, module, *suffix]) in x, - libraries_to_filter.keys())) + filtered_in_modules += list( + filter( + lambda x: "-".join([version, module, *suffix]) in x, libraries_to_filter.keys() + ) + ) for library in list(libraries_to_filter.keys()): if library not in filtered_in_modules: libraries_to_filter.pop(library) @@ -255,15 +270,11 @@ def find_ns3_from_lock_file(lock_file: str) -> (str, list, str): # When we have the lock file, we assemble the correct library names libraries_to_load = [] for module in modules: - library_name = "libns{version}-{module}{suffix}".format( - version=version, - module=module, - suffix=suffix - ) + library_name = f"libns{version}-{module}{suffix}" if library_name not in libraries: - raise Exception("Missing library %s\n" % library_name, - "Build all modules with './ns3 build'" - ) + raise Exception( + f"Missing library {library_name}\n", "Build all modules with './ns3 build'" + ) libraries_to_load.append(libraries[library_name]) return prefix, libraries_to_load, version @@ -282,7 +293,14 @@ def filter_module_name(library: str) -> str: components.pop(0) # Drop build profile suffix and test libraries - if components[-1] in ["debug", "default", "optimized", "release", "relwithdebinfo", "minsizerel"]: + if components[-1] in [ + "debug", + "default", + "optimized", + "release", + "relwithdebinfo", + "minsizerel", + ]: components.pop(-1) return "-".join(components) @@ -337,10 +355,14 @@ def find_ns3_from_search() -> (str, list, str): # Filter out older ns-3 libraries for module in list(modules_to_filter): # Filter duplicates of modules, while excluding test libraries - conflicting_libraries = list(filter(lambda x: module == filter_module_name(x), libraries_to_filter)) + conflicting_libraries = list( + filter(lambda x: module == filter_module_name(x), libraries_to_filter) + ) # Extract versions from conflicting libraries - conflicting_libraries_versions = list(map(lambda x: extract_version(x, module), conflicting_libraries)) + conflicting_libraries_versions = list( + map(lambda x: extract_version(x, module), conflicting_libraries) + ) # Get the newest version found for that library newest_version = get_newest_version(conflicting_libraries_versions) @@ -351,8 +373,9 @@ def find_ns3_from_search() -> (str, list, str): else: newest_version_found = get_newest_version([newest_version, newest_version_found]) if newest_version != newest_version_found: - raise Exception("Incompatible versions of the ns-3 module '%s' were found: %s != %s." - % (module, newest_version, newest_version_found)) + raise Exception( + f"Incompatible versions of the ns-3 module '{module}' were found: {newest_version} != {newest_version_found}." + ) for conflicting_library in list(conflicting_libraries): if "-".join([newest_version, module]) not in conflicting_library: @@ -360,8 +383,9 @@ def find_ns3_from_search() -> (str, list, str): conflicting_libraries.remove(conflicting_library) if len(conflicting_libraries) > 1: - raise Exception("There are multiple build profiles for module '%s'.\nDelete one to continue: %s" - % (module, ", ".join(conflicting_libraries))) + raise Exception( + f"There are multiple build profiles for module '{module}'.\nDelete one to continue: {', '.join(conflicting_libraries)}" + ) return libraries_to_filter, newest_version_found @@ -387,7 +411,9 @@ def load_modules(): libraries = list(map(lambda x: os.path.basename(x), libraries)) for ns3_library in libraries: _, _, linked_libraries = extract_linked_libraries(ns3_library, prefix) - linked_libraries = list(filter(lambda x: "libns3" in x and ns3_library not in x, linked_libraries)) + linked_libraries = list( + filter(lambda x: "libns3" in x and ns3_library not in x, linked_libraries) + ) linked_libraries = list(map(lambda x: os.path.basename(x), linked_libraries)) module_dependencies[os.path.basename(ns3_library)] = linked_libraries @@ -404,19 +430,27 @@ def load_modules(): modules.append(pending_module) return modules - def dependency_order(module_dependencies, pending_modules, current_modules, step_number=0, steps={}): + def dependency_order( + module_dependencies, pending_modules, current_modules, step_number=0, steps={} + ): if len(pending_modules) == 0: return steps if step_number not in steps: steps[step_number] = [] - for module in modules_that_can_be_loaded(module_dependencies, pending_modules, current_modules): + for module in modules_that_can_be_loaded( + module_dependencies, pending_modules, current_modules + ): steps[step_number].append(module) pending_modules.remove(module) current_modules.append(module) - return dependency_order(module_dependencies, pending_modules, current_modules, step_number + 1, steps) + return dependency_order( + module_dependencies, pending_modules, current_modules, step_number + 1, steps + ) sorted_libraries = [] - for step in dependency_order(module_dependencies, list(module_dependencies.keys()), [], 0).values(): + for step in dependency_order( + module_dependencies, list(module_dependencies.keys()), [], 0 + ).values(): sorted_libraries.extend(step) return sorted_libraries @@ -441,7 +475,8 @@ def load_modules(): # Register Ptr<> as a smart pointer import libcppyy - libcppyy.AddSmartPtrType('Ptr') + + libcppyy.AddSmartPtrType("Ptr") # Import ns-3 libraries for variant in ["lib", "lib64"]: @@ -479,7 +514,8 @@ def load_modules(): setattr(cppyy.gbl.ns3, module.replace("-", "_"), cppyy.gbl.ns3) # Set up a few tricks - cppyy.cppdef(""" + cppyy.cppdef( + """ using namespace ns3; bool Time_ge(Time& a, Time& b){ return a >= b;} bool Time_eq(Time& a, Time& b){ return a == b;} @@ -487,7 +523,8 @@ def load_modules(): bool Time_le(Time& a, Time& b){ return a <= b;} bool Time_gt(Time& a, Time& b){ return a > b;} bool Time_lt(Time& a, Time& b){ return a < b;} - """) + """ + ) cppyy.gbl.ns3.Time.__ge__ = cppyy.gbl.Time_ge cppyy.gbl.ns3.Time.__eq__ = cppyy.gbl.Time_eq cppyy.gbl.ns3.Time.__ne__ = cppyy.gbl.Time_ne @@ -508,7 +545,8 @@ def load_modules(): cppyy.gbl.ns3.Node.__del__ = Node_del - cppyy.cppdef(""" + cppyy.cppdef( + """ using namespace ns3; std::tuple LookupByNameFailSafe(std::string name) { @@ -516,44 +554,49 @@ def load_modules(): bool ok = TypeId::LookupByNameFailSafe(name, &id); return std::make_tuple(ok, id); } - """) + """ + ) setattr(cppyy.gbl.ns3, "LookupByNameFailSafe", cppyy.gbl.LookupByNameFailSafe) def CreateObject(className): try: try: - func = "CreateObject%s" % re.sub('[<|>]', '_', className) + func = "CreateObject%s" % re.sub("[<|>]", "_", className) return getattr(cppyy.gbl, func)() except AttributeError: pass try: - func = "Create%s" % re.sub('[<|>]', '_', className) + func = "Create%s" % re.sub("[<|>]", "_", className) return getattr(cppyy.gbl, func)() except AttributeError: pass raise AttributeError except AttributeError: try: - func = "CreateObject%s" % re.sub('[<|>]', '_', className) - cppyy.cppdef(""" + func = "CreateObject%s" % re.sub("[<|>]", "_", className) + cppyy.cppdef( + """ using namespace ns3; Ptr<%s> %s(){ Ptr<%s> object = CreateObject<%s>(); return object; } - """ % (className, func, className, className) - ) + """ + % (className, func, className, className) + ) except Exception as e: try: - func = "Create%s" % re.sub('[<|>]', '_', className) - cppyy.cppdef(""" + func = "Create%s" % re.sub("[<|>]", "_", className) + cppyy.cppdef( + """ using namespace ns3; %s %s(){ %s object = %s(); return object; } - """ % (className, func, className, className) - ) + """ + % (className, func, className, className) + ) except Exception as e: exit(-1) return getattr(cppyy.gbl, func)() @@ -582,10 +625,12 @@ def load_modules(): { return parentPtr->GetObject<%s>(); } - """ % (aggregatedType, aggregatedType, aggregatedType, aggregatedType) + """ + % (aggregatedType, aggregatedType, aggregatedType, aggregatedType) + ) + return cppyy.gbl.getAggregatedObject( + parentObject, aggregatedObject if aggregatedIsClass else aggregatedObject.__class__ ) - return cppyy.gbl.getAggregatedObject(parentObject, - aggregatedObject if aggregatedIsClass else aggregatedObject.__class__) setattr(cppyy.gbl.ns3, "GetObject", GetObject) return cppyy.gbl.ns3 @@ -593,4 +638,4 @@ def load_modules(): # Load all modules and make them available via a built-in ns = load_modules() # can be imported via 'from ns import ns' -builtins.__dict__['ns'] = ns # or be made widely available with 'from ns import *' +builtins.__dict__["ns"] = ns # or be made widely available with 'from ns import *' diff --git a/build-support/3rd-party/colored-messages.cmake b/build-support/3rd-party/colored-messages.cmake index 16a19e2f6..0032715a7 100644 --- a/build-support/3rd-party/colored-messages.cmake +++ b/build-support/3rd-party/colored-messages.cmake @@ -24,21 +24,21 @@ # cmake-format: on # Set empty values for colors -set(ColourReset) -set(Red) -set(Green) -set(Yellow) -set(Blue) -set(Magenta) -set(Cyan) -set(White) -set(BoldRed) -set(BoldGreen) -set(BoldYellow) -set(BoldBlue) -set(BoldMagenta) -set(BoldCyan) -set(BoldWhite) +set(ColourReset "") +set(Red "") +set(Green "") +set(Yellow "") +set(Blue "") +set(Magenta "") +set(Cyan "") +set(White "") +set(BoldRed "") +set(BoldGreen "") +set(BoldYellow "") +set(BoldBlue "") +set(BoldMagenta "") +set(BoldCyan "") +set(BoldWhite "") # Custom message types fallback when not colorized set(HIGHLIGHTED_STATUS STATUS) diff --git a/build-support/3rd-party/find-program-hints.cmake b/build-support/3rd-party/find-program-hints.cmake index 45547a1f1..61106b9e6 100644 --- a/build-support/3rd-party/find-program-hints.cmake +++ b/build-support/3rd-party/find-program-hints.cmake @@ -1,3 +1,4 @@ +disable_cmake_warnings() set(3RD_PARTY_FIND_PROGRAM_HINTS # find_program HINTS for Doxygen # https://gitlab.kitware.com/cmake/cmake/-/blob/master/Modules/FindDoxygen.cmake @@ -18,3 +19,4 @@ set(3RD_PARTY_FIND_PROGRAM_HINTS /Applications/Graphviz.app/Contents/MacOS /Applications/Utilities/Graphviz.app/Contents/MacOS ) +enable_cmake_warnings() diff --git a/build-support/cmake-format-modules.yaml b/build-support/cmake-format-modules.yaml index 963cefa50..8e31ee133 100644 --- a/build-support/cmake-format-modules.yaml +++ b/build-support/cmake-format-modules.yaml @@ -44,6 +44,7 @@ additional_commands: DEPENDENCY_NAME : '1' HEADER_NAME : '1' LIBRARY_NAME : '1' + OUTPUT_VARIABLE : '1' HEADER_NAMES : '*' LIBRARY_NAMES : '*' PATH_SUFFIXES : '*' diff --git a/build-support/cmake-format.yaml b/build-support/cmake-format.yaml index 58d38a3dd..1d2ce71e4 100644 --- a/build-support/cmake-format.yaml +++ b/build-support/cmake-format.yaml @@ -44,10 +44,18 @@ additional_commands: DEPENDENCY_NAME : '1' HEADER_NAME : '1' LIBRARY_NAME : '1' + OUTPUT_VARIABLE : '1' HEADER_NAMES : '*' LIBRARY_NAMES : '*' PATH_SUFFIXES : '*' SEARCH_PATHS : '*' + check_deps: + pargs: + nargs: 1 + kwargs: + CMAKE_PACKAGES : '*' + EXECUTABLES : '*' + PYTHON_PACKAGES : '*' format: tab_size: 2 diff --git a/build-support/compiler-workarounds/ostream-operator-nullptr.h b/build-support/compiler-workarounds/ostream-operator-nullptr.h deleted file mode 100644 index feb6b48b7..000000000 --- a/build-support/compiler-workarounds/ostream-operator-nullptr.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef OSTREAM_OPERATOR_NULLPTR_H -#define OSTREAM_OPERATOR_NULLPTR_H - -#include -#include - -namespace std -{ -inline std::ostream& -operator<<(std::ostream& os, std::nullptr_t) -{ - return os << "nullptr"; // whatever you want nullptr to show up as in the console -} -} // namespace std - -#endif // OSTREAM_OPERATOR_NULLPTR_H diff --git a/build-support/custom-modules/ns3-check-dependencies.cmake b/build-support/custom-modules/ns3-check-dependencies.cmake new file mode 100644 index 000000000..37f6a085d --- /dev/null +++ b/build-support/custom-modules/ns3-check-dependencies.cmake @@ -0,0 +1,59 @@ +# Copyright (c) 2023 Universidade de Brasília +# +# 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: Gabriel Ferreira + +# function used to search for package and program dependencies than store list +# of missing dependencies in the list whose name is stored in missing_deps +function(check_deps missing_deps) + set(multiValueArgs CMAKE_PACKAGES EXECUTABLES PYTHON_PACKAGES) + cmake_parse_arguments("DEPS" "" "" "${multiValueArgs}" ${ARGN}) + + set(local_missing_deps) + # Search for package dependencies + foreach(package ${DEPS_CMAKE_PACKAGES}) + find_package(${package}) + if(NOT ${${package}_FOUND}) + list(APPEND local_missing_deps ${package}) + endif() + endforeach() + + # And for program dependencies + foreach(program ${DEPS_EXECUTABLES}) + # CMake likes to cache find_* to speed things up, so we can't reuse names + # here or it won't check other dependencies + string(TOUPPER ${program} upper_${program}) + mark_as_advanced(${upper_${program}}) + find_program( + ${upper_${program}} ${program} HINTS ${3RD_PARTY_FIND_PROGRAM_HINTS} + ) + if("${${upper_${program}}}" STREQUAL "${upper_${program}}-NOTFOUND") + list(APPEND local_missing_deps ${program}) + endif() + endforeach() + + foreach(package ${DEPS_PYTHON_PACKAGES}) + execute_process( + COMMAND ${Python3_EXECUTABLE} -c "import ${package}" + RESULT_VARIABLE return_code OUTPUT_QUIET ERROR_QUIET + ) + if(NOT (${return_code} EQUAL 0)) + list(APPEND local_missing_deps ${package}) + endif() + endforeach() + + # Store list of missing dependencies in the parent scope + set(${missing_deps} ${local_missing_deps} PARENT_SCOPE) +endfunction() diff --git a/build-support/custom-modules/ns3-cmake-package.cmake b/build-support/custom-modules/ns3-cmake-package.cmake index e441281d7..8b1a7ba09 100644 --- a/build-support/custom-modules/ns3-cmake-package.cmake +++ b/build-support/custom-modules/ns3-cmake-package.cmake @@ -15,6 +15,19 @@ # # Author: Gabriel Ferreira +# Set RPATH not too need LD_LIBRARY_PATH after installing. Add the lib64 variant +# to support all platforms, such as alma linux, used to build the manylinux pip +# wheel. +set(CMAKE_INSTALL_RPATH + "${CMAKE_INSTALL_PREFIX}/lib:$ORIGIN/:$ORIGIN/../lib:${CMAKE_INSTALL_PREFIX}/lib64:$ORIGIN/:$ORIGIN/../lib64" +) + +# cmake-format: off +# You are a wizard, Harry! +# source: https://gitlab.kitware.com/cmake/community/-/wikis/doc/cmake/RPATH-handling +# cmake-format: on +set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) + function(build_required_and_libs_lists module_name visibility libraries all_ns3_libraries ) diff --git a/build-support/custom-modules/ns3-compiler-and-linker-support.cmake b/build-support/custom-modules/ns3-compiler-and-linker-support.cmake new file mode 100644 index 000000000..6861371b8 --- /dev/null +++ b/build-support/custom-modules/ns3-compiler-and-linker-support.cmake @@ -0,0 +1,128 @@ +# Copyright (c) 2023 Universidade de Brasília +# +# 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: Gabriel Ferreira + +# Compiler-specific version checks and flag/feature setting should be done here + +# Identify compiler and check version +set(below_minimum_msg "compiler is below the minimum required version") +set(CLANG FALSE) +if("${CMAKE_CXX_COMPILER_ID}" MATCHES "AppleClang") + if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS ${AppleClang_MinVersion}) + message( + FATAL_ERROR + "Apple Clang ${CMAKE_CXX_COMPILER_VERSION} ${below_minimum_msg} ${AppleClang_MinVersion}" + ) + endif() + set(CLANG TRUE) +endif() + +if((NOT CLANG) AND ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")) + if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS ${Clang_MinVersion}) + message( + FATAL_ERROR + "Clang ${CMAKE_CXX_COMPILER_VERSION} ${below_minimum_msg} ${Clang_MinVersion}" + ) + endif() + set(CLANG TRUE) +endif() + +if(CLANG) + if(${NS3_COLORED_OUTPUT} OR "$ENV{CLICOLOR}") + add_definitions(-fcolor-diagnostics) # colorize clang++ output + endif() +endif() + +set(GCC FALSE) +if("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") + if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS ${GNU_MinVersion}) + message( + FATAL_ERROR + "GNU ${CMAKE_CXX_COMPILER_VERSION} ${below_minimum_msg} ${GNU_MinVersion}" + ) + endif() + if((CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "12.2.0")) + # PCH causes weird errors on certain versions of GCC when C++20 is enabled + # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106799 + set(NS3_PRECOMPILE_HEADERS OFF + CACHE BOOL "Precompile module headers to speed up compilation" FORCE + ) + endif() + if((CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "12.1.0") + AND (CMAKE_CXX_COMPILER_VERSION VERSION_LESS "12.3.2") + ) + # Disable warnings-as-errors for certain versions of GCC when C++20 is + # enabled https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105545 + add_compile_options(-Wno-restrict) + endif() + set(GCC TRUE) + add_definitions(-fno-semantic-interposition) + if(${NS3_COLORED_OUTPUT} OR "$ENV{CLICOLOR}") + add_definitions(-fdiagnostics-color=always) # colorize g++ output + endif() +endif() +unset(below_minimum_msg) + +set(LIB_AS_NEEDED_PRE "") +set(LIB_AS_NEEDED_POST "") +set(STATIC_LINK_FLAGS -static -static-libstdc++ -static-libgcc) +if(${GCC} AND NOT APPLE) + # using GCC + set(LIB_AS_NEEDED_PRE -Wl,--no-as-needed) + set(LIB_AS_NEEDED_POST -Wl,--as-needed) + set(LIB_AS_NEEDED_PRE_STATIC -Wl,--whole-archive,-Bstatic) + set(LIB_AS_NEEDED_POST_STATIC -Wl,--no-whole-archive) + set(LIB_AS_NEEDED_POST_STATIC_DYN -Wl,-Bdynamic,--no-whole-archive) +endif() + +if(${CLANG} AND APPLE) + # using Clang set(LIB_AS_NEEDED_PRE -all_load) + set(LIB_AS_NEEDED_POST "") + set(LIB_AS_NEEDED_PRE_STATIC -Wl,-all_load) + set(STATIC_LINK_FLAGS "") +endif() + +if(${NS3_FAST_LINKERS}) + # Search for faster linkers mold and lld, and use them if available + mark_as_advanced(MOLD LLD) + find_program(MOLD mold) + find_program(LLD ld.lld) + + # USING_FAST_LINKER will be defined if a fast linker is being used and its + # content will correspond to the fast linker name + + # Mold support was added in GCC 12.1.0 + if(NOT USING_FAST_LINKER + AND NOT (${MOLD} STREQUAL "MOLD-NOTFOUND") + AND LINUX + AND ${GCC} + AND (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 12.1.0) + ) + set(USING_FAST_LINKER MOLD) + add_link_options("-fuse-ld=mold") + endif() + + if(NOT USING_FAST_LINKER AND NOT (${LLD} STREQUAL "LLD-NOTFOUND") + AND (${GCC} OR ${CLANG}) + ) + set(USING_FAST_LINKER LLD) + add_link_options("-fuse-ld=lld") + if(WIN32) + # Clear unsupported linker flags on Windows + set(LIB_AS_NEEDED_PRE "") + endif() + endif() +endif() diff --git a/build-support/custom-modules/ns3-compiler-workarounds.cmake b/build-support/custom-modules/ns3-compiler-workarounds.cmake index 42e8d9dbe..f544ddff2 100644 --- a/build-support/custom-modules/ns3-compiler-workarounds.cmake +++ b/build-support/custom-modules/ns3-compiler-workarounds.cmake @@ -17,39 +17,7 @@ include(CheckCXXSourceCompiles) -# Clang 6, 7 and 8 shipped with incomplete C++17 features and do not handle -# ostream& operator<<(ostream& os, nullptr_t ptr) -# https://gitlab.com/nsnam/ns-3-dev/-/issues/730 -check_cxx_source_compiles( - " - #include - #include - inline std::ostream& operator << (std::ostream& os, std::nullptr_t ptr) - { - return os << \"nullptr\"; //whatever you want nullptr to show up as in the console - } - int main() - { - std::ostream os(NULL); - os << std::nullptr_t(); - return 0; - } - " - MISSING_OSTREAM_NULLPTR_OPERATOR -) - -if(${MISSING_OSTREAM_NULLPTR_OPERATOR}) - message( - ${HIGHLIGHTED_STATUS} - "Using compiler workaround: compiling in \"ostream& operator<<(ostream&, nullptr_t)\"" - ) - add_definitions( - -include - ${CMAKE_CURRENT_SOURCE_DIR}/build-support/compiler-workarounds/ostream-operator-nullptr.h - ) -endif() - -# Some compilers (e.g. GCC < 9.1 and Clang < 9) do not link +# Some compilers (e.g. GCC < 9.1) do not link # std::filesystem/std::experimental::filesystem by default. If the sample # program can be linked, it means it is indeed linked by default. Otherwise, we # link it manually. https://en.cppreference.com/w/cpp/filesystem diff --git a/build-support/custom-modules/ns3-executables.cmake b/build-support/custom-modules/ns3-executables.cmake new file mode 100644 index 000000000..92ccea1a8 --- /dev/null +++ b/build-support/custom-modules/ns3-executables.cmake @@ -0,0 +1,162 @@ +function(set_runtime_outputdirectory target_name output_directory target_prefix) + # Prevent duplicate '/' in EXECUTABLE_DIRECTORY_PATH, since it gets translated + # to doubled underlines and will cause the ns3 script to fail + string(REPLACE "//" "/" output_directory "${output_directory}") + + set(ns3-exec-outputname ns${NS3_VER}-${target_name}${build_profile_suffix}) + set(ns3-execs "${output_directory}${ns3-exec-outputname};${ns3-execs}" + CACHE INTERNAL "list of c++ executables" + ) + set(ns3-execs-clean "${target_prefix}${target_name};${ns3-execs-clean}" + CACHE INTERNAL + "list of c++ executables without version prefix and build suffix" + ) + + set_target_properties( + ${target_prefix}${target_name} + PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${output_directory} + RUNTIME_OUTPUT_NAME ${ns3-exec-outputname} + ) + if(${XCODE}) + # Is that so hard not to break people's CI, AAPL?? Why would you output the + # targets to a Debug/Release subfolder? Why? + foreach(OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES}) + string(TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG) + set_target_properties( + ${target_prefix}${target_name} + PROPERTIES RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${output_directory} + RUNTIME_OUTPUT_NAME_${OUTPUTCONFIG} ${ns3-exec-outputname} + ) + endforeach(OUTPUTCONFIG CMAKE_CONFIGURATION_TYPES) + endif() + + if(${ENABLE_TESTS}) + add_dependencies(all-test-targets ${target_prefix}${target_name}) + # Create a CTest entry for each executable + if(WIN32) + # Windows require this workaround to make sure the DLL files are located + add_test( + NAME ctest-${target_prefix}${target_name} + COMMAND + ${CMAKE_COMMAND} -E env + "PATH=$ENV{PATH};${CMAKE_RUNTIME_OUTPUT_DIRECTORY};${CMAKE_LIBRARY_OUTPUT_DIRECTORY}" + ${ns3-exec-outputname} + WORKING_DIRECTORY ${output_directory} + ) + else() + add_test(NAME ctest-${target_prefix}${target_name} + COMMAND ${ns3-exec-outputname} + WORKING_DIRECTORY ${output_directory} + ) + endif() + endif() + + if(${NS3_CLANG_TIMETRACE}) + add_dependencies(timeTraceReport ${target_prefix}${target_name}) + endif() +endfunction(set_runtime_outputdirectory) + +function(get_scratch_prefix prefix) + # /path/to/ns-3-dev/scratch/nested-subdir + set(temp ${CMAKE_CURRENT_SOURCE_DIR}) + # remove /path/to/ns-3-dev/ to get scratch/nested-subdir + string(REPLACE "${PROJECT_SOURCE_DIR}/" "" temp "${temp}") + # replace path separators with underlines + string(REPLACE "/" "_" temp "${temp}") + # save the prefix value to the passed variable + set(${prefix} ${temp}_ PARENT_SCOPE) +endfunction() + +function(build_exec) + # Argument parsing + set(options IGNORE_PCH STANDALONE) + set(oneValueArgs EXECNAME EXECNAME_PREFIX EXECUTABLE_DIRECTORY_PATH + INSTALL_DIRECTORY_PATH + ) + set(multiValueArgs SOURCE_FILES HEADER_FILES LIBRARIES_TO_LINK DEFINITIONS) + cmake_parse_arguments( + "BEXEC" "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} + ) + + # Resolve nested scratch prefixes without user intervention + string(REPLACE "${PROJECT_SOURCE_DIR}" "" relative_path + "${CMAKE_CURRENT_SOURCE_DIR}" + ) + if("${relative_path}" MATCHES "scratch" AND "${BEXEC_EXECNAME_PREFIX}" + STREQUAL "" + ) + get_scratch_prefix(BEXEC_EXECNAME_PREFIX) + endif() + + add_executable( + ${BEXEC_EXECNAME_PREFIX}${BEXEC_EXECNAME} "${BEXEC_SOURCE_FILES}" + ) + + target_compile_definitions( + ${BEXEC_EXECNAME_PREFIX}${BEXEC_EXECNAME} PUBLIC ${BEXEC_DEFINITIONS} + ) + + if(${PRECOMPILE_HEADERS_ENABLED} AND (NOT ${BEXEC_IGNORE_PCH})) + target_precompile_headers( + ${BEXEC_EXECNAME_PREFIX}${BEXEC_EXECNAME} REUSE_FROM stdlib_pch_exec + ) + endif() + + if(${NS3_STATIC} AND (NOT BEXEC_STANDALONE)) + target_link_libraries( + ${BEXEC_EXECNAME_PREFIX}${BEXEC_EXECNAME} ${LIB_AS_NEEDED_PRE_STATIC} + ${lib-ns3-static} + ) + elseif(${NS3_MONOLIB} AND (NOT BEXEC_STANDALONE)) + target_link_libraries( + ${BEXEC_EXECNAME_PREFIX}${BEXEC_EXECNAME} ${LIB_AS_NEEDED_PRE} + ${lib-ns3-monolib} ${LIB_AS_NEEDED_POST} + ) + else() + target_link_libraries( + ${BEXEC_EXECNAME_PREFIX}${BEXEC_EXECNAME} ${LIB_AS_NEEDED_PRE} + "${BEXEC_LIBRARIES_TO_LINK}" ${LIB_AS_NEEDED_POST} + ) + endif() + + set_runtime_outputdirectory( + "${BEXEC_EXECNAME}" "${BEXEC_EXECUTABLE_DIRECTORY_PATH}/" + "${BEXEC_EXECNAME_PREFIX}" + ) + + if(BEXEC_INSTALL_DIRECTORY_PATH) + install(TARGETS ${BEXEC_EXECNAME_PREFIX}${BEXEC_EXECNAME} + EXPORT ns3ExportTargets + RUNTIME DESTINATION ${BEXEC_INSTALL_DIRECTORY_PATH} + ) + get_property( + filename TARGET ${BEXEC_EXECNAME_PREFIX}${BEXEC_EXECNAME} + PROPERTY RUNTIME_OUTPUT_NAME + ) + add_custom_target( + uninstall_${BEXEC_EXECNAME_PREFIX}${BEXEC_EXECNAME} + COMMAND + rm ${CMAKE_INSTALL_PREFIX}/${BEXEC_INSTALL_DIRECTORY_PATH}/${filename} + ) + add_dependencies( + uninstall uninstall_${BEXEC_EXECNAME_PREFIX}${BEXEC_EXECNAME} + ) + endif() +endfunction(build_exec) + +function(scan_python_examples path) + # Skip python examples search in case the bindings are disabled + if(NOT ${ENABLE_PYTHON_BINDINGS}) + return() + endif() + + # Search for python examples + file(GLOB_RECURSE python_examples ${path}/*.py) + foreach(python_example ${python_examples}) + if(NOT (${python_example} MATCHES "examples-to-run")) + set(ns3-execs-py "${python_example};${ns3-execs-py}" + CACHE INTERNAL "list of python scripts" + ) + endif() + endforeach() +endfunction() diff --git a/build-support/custom-modules/ns3-fetch-optional-modules-dependencies.cmake b/build-support/custom-modules/ns3-fetch-optional-modules-dependencies.cmake index 90f774361..6f5702cfc 100644 --- a/build-support/custom-modules/ns3-fetch-optional-modules-dependencies.cmake +++ b/build-support/custom-modules/ns3-fetch-optional-modules-dependencies.cmake @@ -2,13 +2,11 @@ include(ExternalProject) ExternalProject_Add( brite_dep - URL https://code.nsnam.org/BRITE/archive/30338f4f63b9.zip - URL_HASH MD5=b36ecf8f6b5f2cfae936ba1f1bfcff5c + GIT_REPOSITORY https://gitlab.com/nsnam/BRITE.git + GIT_TAG 29c301e828d2a4f303b3d0c69360c987b02d0745 PREFIX brite_dep BUILD_IN_SOURCE TRUE - CONFIGURE_COMMAND make - BUILD_COMMAND make - INSTALL_COMMAND make install PREFIX=${CMAKE_OUTPUT_DIRECTORY} + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_OUTPUT_DIRECTORY} ) ExternalProject_Add( @@ -18,21 +16,40 @@ ExternalProject_Add( PREFIX click_dep BUILD_IN_SOURCE TRUE UPDATE_DISCONNECTED TRUE - CONFIGURE_COMMAND ./configure --disable-linuxmodule --enable-nsclick - --enable-wifi --prefix ${CMAKE_OUTPUT_DIRECTORY} + CONFIGURE_COMMAND + ./configure --disable-linuxmodule --enable-nsclick --enable-wifi --prefix + ${CMAKE_OUTPUT_DIRECTORY} --libdir ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} BUILD_COMMAND make -j${NumThreads} INSTALL_COMMAND make install ) ExternalProject_Add( openflow_dep - URL https://code.nsnam.org/openflow/archive/d45e7d184151.zip - URL_HASH MD5=a068cdaec5523586921b2f1f81f10916 + GIT_REPOSITORY https://gitlab.com/nsnam/openflow.git + GIT_TAG 4869d4f6900342440af02ea93a3d8040c8316e5f PREFIX openflow_dep BUILD_IN_SOURCE TRUE - CONFIGURE_COMMAND ./waf configure --prefix ${CMAKE_OUTPUT_DIRECTORY} - BUILD_COMMAND ./waf build - INSTALL_COMMAND ./waf install + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_OUTPUT_DIRECTORY} +) + +find_file( + BOOST_STATIC_ASSERT + NAMES static_assert.hpp + PATH_SUFFIXES boost + HINTS /usr/local +) + +if(${BOOST_STATIC_ASSERT} STREQUAL "BOOST_STATIC_ASSERT-NOTFOUND") + message(FATAL_ERROR "Boost static assert is required by openflow") +endif() + +get_filename_component(boost_dir ${BOOST_STATIC_ASSERT} DIRECTORY) + +install( + DIRECTORY ${boost_dir} + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + USE_SOURCE_PERMISSIONS + PATTERN "boost/*" ) install( @@ -56,11 +73,12 @@ install( USE_SOURCE_PERMISSIONS PATTERN "boost/*" ) + install( - DIRECTORY ${CMAKE_OUTPUT_DIRECTORY}/lib/ + DIRECTORY ${CMAKE_OUTPUT_DIRECTORY}/${libdir}/ DESTINATION ${CMAKE_INSTALL_LIBDIR} USE_SOURCE_PERMISSIONS - PATTERN "lib/*" + PATTERN "${libdir}/*" ) macro(add_dependency_to_optional_modules_dependencies) diff --git a/build-support/custom-modules/ns3-filter-modules.cmake b/build-support/custom-modules/ns3-filter-modules.cmake new file mode 100644 index 000000000..9c79ace9d --- /dev/null +++ b/build-support/custom-modules/ns3-filter-modules.cmake @@ -0,0 +1,233 @@ +# Copyright (c) 2023 Universidade de Brasília +# +# 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: Gabriel Ferreira + +# This is where recursive module dependency checking is implemented for +# filtering enabled and disabled modules + +function(filter_modules modules_to_filter all_modules_list filter_in) + set(new_modules_to_build) + # We are receiving variable names as arguments, so we have to "dereference" + # them first That is why we have the duplicated ${${}} + foreach(module ${${all_modules_list}}) + if(${filter_in} (${module} IN_LIST ${modules_to_filter})) + list(APPEND new_modules_to_build ${module}) + endif() + endforeach() + set(${all_modules_list} ${new_modules_to_build} PARENT_SCOPE) +endfunction() + +function(resolve_dependencies module_name dependencies contrib_dependencies) + # Create cache variables to hold dependencies list and visited + set(dependency_visited "" CACHE INTERNAL "") + set(contrib_dependency_visited "" CACHE INTERNAL "") + recursive_dependency(${module_name}) + if(${module_name} IN_LIST dependency_visited) + set(temp ${dependency_visited}) + list(REMOVE_AT temp 0) + set(${dependencies} ${temp} PARENT_SCOPE) + set(${contrib_dependencies} ${contrib_dependency_visited} PARENT_SCOPE) + else() + set(temp ${contrib_dependency_visited}) + list(REMOVE_AT temp 0) + set(${dependencies} ${dependency_visited} PARENT_SCOPE) + set(${contrib_dependencies} ${temp} PARENT_SCOPE) + endif() + unset(dependency_visited CACHE) + unset(contrib_dependency_visited CACHE) +endfunction() + +function(filter_libraries cmakelists_contents libraries) + string(REGEX MATCHALL "{lib[^}]*[^obj]}" matches "${cmakelists_content}") + list(REMOVE_ITEM matches "{libraries_to_link}") + string(REPLACE "{lib\${name" "" matches "${matches}") # special case for + # src/test + string(REPLACE "{lib" "" matches "${matches}") + string(REPLACE "}" "" matches "${matches}") + set(${libraries} ${matches} PARENT_SCOPE) +endfunction() + +function(recursive_dependency module_name) + # Read module CMakeLists.txt and search for ns-3 modules + set(src_cmakelist ${PROJECT_SOURCE_DIR}/src/${module_name}/CMakeLists.txt) + set(contrib_cmakelist + ${PROJECT_SOURCE_DIR}/contrib/${module_name}/CMakeLists.txt + ) + set(contrib FALSE) + if(EXISTS ${src_cmakelist}) + file(READ ${src_cmakelist} cmakelists_content) + elseif(EXISTS ${contrib_cmakelist}) + file(READ ${contrib_cmakelist} cmakelists_content) + set(contrib TRUE) + else() + set(cmakelists_content "") + message(${HIGHLIGHTED_STATUS} + "The CMakeLists.txt file for module ${module_name} was not found." + ) + endif() + + filter_libraries("${cmakelists_content}" matches) + + # Add this visited module dependencies to the dependencies list + if(contrib) + set(contrib_dependency_visited + "${contrib_dependency_visited};${module_name}" CACHE INTERNAL "" + ) + set(examples_cmakelists ${contrib_cmakelist}) + else() + set(dependency_visited "${dependency_visited};${module_name}" CACHE INTERNAL + "" + ) + set(examples_cmakelists ${src_cmakelist}) + endif() + + # cmake-format: off + # Scan dependencies required by this module examples + set(example_matches) + #if(${ENABLE_EXAMPLES}) + # string(REPLACE "${module_name}" "${module_name}/examples" examples_cmakelists ${examples_cmakelists}) + # if(EXISTS ${examples_cmakelists}) + # file(READ ${examples_cmakelists} cmakelists_content) + # filter_libraries(${cmakelists_content} example_matches) + # endif() + #endif() + # cmake-format: on + + # For each dependency, call this same function + set(matches "${matches};${example_matches}") + foreach(match ${matches}) + if(NOT ((${match} IN_LIST dependency_visited) + OR (${match} IN_LIST contrib_dependency_visited)) + ) + recursive_dependency(${match}) + endif() + endforeach() +endfunction() + +macro( + filter_enabled_and_disabled_modules + libs_to_build + contrib_libs_to_build + NS3_ENABLED_MODULES + NS3_DISABLED_MODULES + ns3rc_enabled_modules + ns3rc_disabled_modules +) + mark_as_advanced(ns3-all-enabled-modules) + + # Before filtering, we set a variable with all scanned modules in the src + # directory + set(scanned_modules ${${libs_to_build}}) + + # Ensure enabled and disable modules lists are using semicolons + string(REPLACE "," ";" ${NS3_ENABLED_MODULES} "${${NS3_ENABLED_MODULES}}") + string(REPLACE "," ";" ${NS3_DISABLED_MODULES} "${${NS3_DISABLED_MODULES}}") + + # Now that scanning modules finished, we can remove the disabled modules or + # replace the modules list with the ones in the enabled list + if(${NS3_ENABLED_MODULES} OR ${ns3rc_enabled_modules}) + # List of enabled modules passed by the command line overwrites list read + # from ns3rc + if(${NS3_ENABLED_MODULES}) + set(ns3rc_enabled_modules ${${NS3_ENABLED_MODULES}}) + endif() + + # Filter enabled modules + filter_modules(ns3rc_enabled_modules libs_to_build "") + filter_modules(ns3rc_enabled_modules contrib_libs_to_build "") + + # Use recursion to automatically determine dependencies required by the + # manually enabled modules + foreach(lib ${${contrib_libs_to_build}}) + resolve_dependencies(${lib} dependencies contrib_dependencies) + list(APPEND ${contrib_libs_to_build} "${contrib_dependencies}") + list(APPEND ${libs_to_build} "${dependencies}") + unset(dependencies) + unset(contrib_dependencies) + endforeach() + + foreach(lib ${${libs_to_build}}) + resolve_dependencies(${lib} dependencies contrib_dependencies) + list(APPEND ${libs_to_build} "${dependencies}") + unset(dependencies) + unset(contrib_dependencies) + endforeach() + endif() + + if(${NS3_DISABLED_MODULES} OR ${ns3rc_disabled_modules}) + # List of disabled modules passed by the command line overwrites list read + # from ns3rc + + if(${NS3_DISABLED_MODULES}) + set(ns3rc_disabled_modules ${${NS3_DISABLED_MODULES}}) + endif() + + set(all_libs ${${libs_to_build}};${${contrib_libs_to_build}}) + + # We then use the recursive dependency finding to get all dependencies of + # all modules + foreach(lib ${all_libs}) + resolve_dependencies(${lib} dependencies contrib_dependencies) + set(${lib}_dependencies "${dependencies};${contrib_dependencies}") + unset(dependencies) + unset(contrib_dependencies) + endforeach() + + # Now we can begin removing libraries that require disabled dependencies + set(disabled_libs "${${ns3rc_disabled_modules}}") + foreach(libo ${all_libs}) + foreach(lib ${all_libs}) + foreach(disabled_lib ${disabled_libs}) + if(${lib} STREQUAL ${disabled_lib}) + continue() + endif() + if(${disabled_lib} IN_LIST ${lib}_dependencies) + list(APPEND disabled_libs ${lib}) + break() # proceed to the next lib in all_libs + endif() + endforeach() + endforeach() + endforeach() + + # Clean dependencies lists + foreach(lib ${all_libs}) + unset(${lib}_dependencies) + endforeach() + + # We can filter out disabled modules + filter_modules(disabled_libs libs_to_build "NOT") + filter_modules(disabled_libs contrib_libs_to_build "NOT") + + if(core IN_LIST ${libs_to_build}) + list(APPEND ${libs_to_build} test) # include test module + endif() + endif() + + # Older CMake versions require this workaround for empty lists + if(NOT ${contrib_libs_to_build}) + set(${contrib_libs_to_build} "") + endif() + + # Filter out any eventual duplicates + list(REMOVE_DUPLICATES ${libs_to_build}) + list(REMOVE_DUPLICATES ${contrib_libs_to_build}) + + # Export list with all enabled modules (used to separate ns libraries from + # non-ns libraries in ns3_module_macros) + set(ns3-all-enabled-modules "${${libs_to_build}};${${contrib_libs_to_build}}" + CACHE INTERNAL "list with all enabled modules" + ) +endmacro() diff --git a/build-support/custom-modules/ns3-find-external-library.cmake b/build-support/custom-modules/ns3-find-external-library.cmake new file mode 100644 index 000000000..1d7506310 --- /dev/null +++ b/build-support/custom-modules/ns3-find-external-library.cmake @@ -0,0 +1,339 @@ +# Copyright (c) 2023 Universidade de Brasília +# +# 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: Gabriel Ferreira + +# This is our own variant of find_package, for CMake and non-CMake based +# projects +function(log_find_searched_paths) + # Parse arguments + set(options) + set(oneValueArgs TARGET_TYPE TARGET_NAME SEARCH_RESULT SEARCH_SYSTEM_PREFIX) + set(multiValueArgs SEARCH_PATHS SEARCH_SUFFIXES) + cmake_parse_arguments( + "LOGFIND" "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} + ) + + # Get searched paths and add cmake_system_prefix_path if not explicitly marked + # not to include it + set(tsearch_paths ${LOGFIND_SEARCH_PATHS}) + if("${LOGFIND_SEARCH_SYSTEM_PREFIX}" STREQUAL "") + list(APPEND tsearch_paths "${CMAKE_SYSTEM_PREFIX_PATH}") + endif() + + set(log_find + "Looking for ${LOGFIND_TARGET_TYPE} ${LOGFIND_TARGET_NAME} in:\n" + ) + # For each search path and suffix combination, print a line + foreach(tsearch_path ${tsearch_paths}) + foreach(suffix ${LOGFIND_SEARCH_SUFFIXES}) + string(APPEND log_find + "\t${tsearch_path}${suffix}/${LOGFIND_TARGET_NAME}\n" + ) + endforeach() + endforeach() + + # Add a final line saying if the file was found and where, or if it was not + # found + if("${${LOGFIND_SEARCH_RESULT}}" STREQUAL "${LOGFIND_SEARCH_RESULT}-NOTFOUND") + string(APPEND log_find + "\n\t${LOGFIND_TARGET_TYPE} ${LOGFIND_TARGET_NAME} was not found\n" + ) + else() + string( + APPEND + log_find + "\n\t${LOGFIND_TARGET_TYPE} ${LOGFIND_TARGET_NAME} was found in ${${LOGFIND_SEARCH_RESULT}}\n" + ) + endif() + + # Replace duplicate path separators + string(REPLACE "//" "/" log_find "${log_find}") + + # Print find debug message similar to the one produced by + # CMAKE_FIND_DEBUG_MODE=true in CMake >= 3.17 + message(STATUS ${log_find}) +endfunction() + +function(find_external_library) + # Parse arguments + set(options QUIET) + set(oneValueArgs DEPENDENCY_NAME HEADER_NAME LIBRARY_NAME OUTPUT_VARIABLE) + set(multiValueArgs HEADER_NAMES LIBRARY_NAMES PATH_SUFFIXES SEARCH_PATHS) + cmake_parse_arguments( + "FIND_LIB" "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} + ) + + # Set the external package/dependency name + set(name ${FIND_LIB_DEPENDENCY_NAME}) + + # We process individual and list of headers and libraries by transforming them + # into lists + set(library_names "${FIND_LIB_LIBRARY_NAME};${FIND_LIB_LIBRARY_NAMES}") + set(header_names "${FIND_LIB_HEADER_NAME};${FIND_LIB_HEADER_NAMES}") + + # Just changing the parsed argument name back to something shorter + set(search_paths ${FIND_LIB_SEARCH_PATHS}) + set(path_suffixes "${FIND_LIB_PATH_SUFFIXES}") + + set(not_found_libraries) + set(library_dirs) + set(libraries) + + # Include parent directories in the search paths to handle Bake cases + get_filename_component(parent_project_dir ${PROJECT_SOURCE_DIR} DIRECTORY) + get_filename_component( + grandparent_project_dir ${parent_project_dir} DIRECTORY + ) + set(project_parent_dirs ${parent_project_dir} ${grandparent_project_dir}) + + # Paths and suffixes where libraries will be searched on + disable_cmake_warnings() + set(library_search_paths + ${search_paths} + ${project_parent_dirs} + ${CMAKE_OUTPUT_DIRECTORY} # Search for libraries in ns-3-dev/build + ${CMAKE_INSTALL_PREFIX} # Search for libraries in the install directory + # (e.g. /usr/) + $ENV{LD_LIBRARY_PATH} # Search for libraries in LD_LIBRARY_PATH + # directories + $ENV{PATH} # Search for libraries in PATH directories + ) + enable_cmake_warnings() + # cmake-format: off + # + # Split : separated entries from environment variables + # by replacing separators with ; + # + # cmake-format: on + string(REPLACE ":" ";" library_search_paths "${library_search_paths}") + + set(suffixes /build /lib /build/lib / /bin ${path_suffixes}) + + # For each of the library names in LIBRARY_NAMES or LIBRARY_NAME + foreach(library ${library_names}) + # We mark this value is advanced not to pollute the configuration with + # ccmake with the cache variables used internally + mark_as_advanced(${name}_library_internal_${library}) + + # We search for the library named ${library} and store the results in + # ${name}_library_internal_${library} + find_library( + ${name}_library_internal_${library} ${library} + HINTS ${library_search_paths} PATH_SUFFIXES ${suffixes} + ) + # cmake-format: off + # Note: the PATH_SUFFIXES above apply to *ALL* PATHS and HINTS Which + # translates to CMake searching on standard library directories + # CMAKE_SYSTEM_PREFIX_PATH, user-settable CMAKE_PREFIX_PATH or + # CMAKE_LIBRARY_PATH and the directories listed above + # + # e.g. from Ubuntu 22.04 CMAKE_SYSTEM_PREFIX_PATH = + # /usr/local;/usr;/;/usr/local;/usr/X11R6;/usr/pkg;/opt + # + # Searched directories without suffixes + # + # ${CMAKE_SYSTEM_PREFIX_PATH}[0] = /usr/local/ + # ${CMAKE_SYSTEM_PREFIX_PATH}[1] = /usr + # ${CMAKE_SYSTEM_PREFIX_PATH}[2] = / + # ... + # ${CMAKE_SYSTEM_PREFIX_PATH}[6] = /opt + # ${LD_LIBRARY_PATH}[0] + # ... + # ${LD_LIBRARY_PATH}[m] + # ${PATH}[0] + # ... + # ${PATH}[m] + # + # Searched directories with suffixes include all of the directories above + # plus all suffixes + # PATH_SUFFIXES /build /lib /build/lib / /bin # ${path_suffixes} + # + # /usr/local/build + # /usr/local/lib + # /usr/local/build/lib + # /usr/local/bin + # ... + # + # cmake-format: on + # Or enable NS3_VERBOSE to print the searched paths + + # Print tested paths to the searched library and if it was found + if(${NS3_VERBOSE} AND (${CMAKE_VERSION} VERSION_LESS "3.17.0")) + log_find_searched_paths( + TARGET_TYPE + Library + TARGET_NAME + ${library} + SEARCH_RESULT + ${name}_library_internal_${library} + SEARCH_PATHS + ${library_search_paths} + SEARCH_SUFFIXES + ${suffixes} + ) + endif() + + # After searching the library, the internal variable should have either the + # absolute path to the library or the name of the variable appended with + # -NOTFOUND + if("${${name}_library_internal_${library}}" STREQUAL + "${name}_library_internal_${library}-NOTFOUND" + ) + # We keep track of libraries that were not found + list(APPEND not_found_libraries ${library}) + else() + # We get the name of the parent directory of the library and append the + # library to a list of found libraries + get_filename_component( + ${name}_library_dir_internal ${${name}_library_internal_${library}} + DIRECTORY + ) # e.g. lib/openflow.(so|dll|dylib|a) -> lib + list(APPEND library_dirs ${${name}_library_dir_internal}) + list(APPEND libraries ${${name}_library_internal_${library}}) + endif() + endforeach() + + # For each library that was found (e.g. /usr/lib/pthread.so), get their parent + # directory (/usr/lib) and its parent (/usr) + set(parent_dirs) + foreach(libdir ${library_dirs}) + get_filename_component(parent_libdir ${libdir} DIRECTORY) + get_filename_component(parent_parent_libdir ${parent_libdir} DIRECTORY) + list(APPEND parent_dirs ${libdir} ${parent_libdir} ${parent_parent_libdir}) + endforeach() + + set(header_search_paths + ${search_paths} + ${parent_dirs} + ${project_parent_dirs} + ${CMAKE_OUTPUT_DIRECTORY} # Search for headers in + # ns-3-dev/build + ${CMAKE_INSTALL_PREFIX} # Search for headers in the install + ) + + set(not_found_headers) + set(include_dirs) + foreach(header ${header_names}) + # The same way with libraries, we mark the internal variable as advanced not + # to pollute ccmake configuration with variables used internally + mark_as_advanced(${name}_header_internal_${header}) + set(suffixes + /build + /include + /build/include + /build/include/${name} + /include/${name} + /${name} + / + ${path_suffixes} + ) + + # cmake-format: off + # Here we search for the header file named ${header} and store the result in + # ${name}_header_internal_${header} + # + # The same way we did with libraries, here we search on + # CMAKE_SYSTEM_PREFIX_PATH, along with user-settable ${search_paths}, the + # parent directories from the libraries, CMAKE_OUTPUT_DIRECTORY and + # CMAKE_INSTALL_PREFIX + # + # And again, for each of them, for every suffix listed /usr/local/build + # /usr/local/include + # /usr/local/build/include + # /usr/local/build/include/${name} + # /usr/local/include/${name} + # ... + # + # cmake-format: on + # Or enable NS3_VERBOSE to get the searched paths printed while configuring + + find_file(${name}_header_internal_${header} ${header} + HINTS ${header_search_paths} # directory (e.g. /usr/) + PATH_SUFFIXES ${suffixes} + ) + + # Print tested paths to the searched header and if it was found + if(${NS3_VERBOSE} AND (${CMAKE_VERSION} VERSION_LESS "3.17.0")) + log_find_searched_paths( + TARGET_TYPE + Header + TARGET_NAME + ${header} + SEARCH_RESULT + ${name}_header_internal_${header} + SEARCH_PATHS + ${header_search_paths} + SEARCH_SUFFIXES + ${suffixes} + ) + endif() + + # If the header file was not found, append to the not-found list + if("${${name}_header_internal_${header}}" STREQUAL + "${name}_header_internal_${header}-NOTFOUND" + ) + list(APPEND not_found_headers ${header}) + else() + # If the header file was found, get their directories and the parent of + # their directories to add as include directories + get_filename_component( + header_include_dir ${${name}_header_internal_${header}} DIRECTORY + ) # e.g. include/click/ (simclick.h) -> #include should work + get_filename_component( + header_include_dir2 ${header_include_dir} DIRECTORY + ) # e.g. include/(click) -> #include should work + list(APPEND include_dirs ${header_include_dir} ${header_include_dir2}) + endif() + endforeach() + + # Remove duplicate include directories + if(include_dirs) + list(REMOVE_DUPLICATES include_dirs) + endif() + + # If we find both library and header, we export their values + if((NOT not_found_libraries) AND (NOT not_found_headers)) + set(${name}_INCLUDE_DIRS "${include_dirs}" PARENT_SCOPE) + set(${name}_LIBRARIES "${libraries}" PARENT_SCOPE) + set(${name}_FOUND TRUE PARENT_SCOPE) + if(NOT ${FIND_LIB_QUIET}) + message(STATUS "find_external_library: ${name} was found.") + endif() + else() + set(${name}_INCLUDE_DIRS PARENT_SCOPE) + set(${name}_LIBRARIES PARENT_SCOPE) + set(${name}_FOUND FALSE PARENT_SCOPE) + + set(missing_components + "Missing headers: \"${not_found_headers}\" and missing libraries: \"${not_found_libraries}\"" + ) + + # Propagate missing components to the specified variable + if(DEFINED FIND_LIB_OUTPUT_VARIABLE) + mark_as_advanced(${FIND_LIB_OUTPUT_VARIABLE}) + set(${FIND_LIB_OUTPUT_VARIABLE} "${missing_components}" CACHE INTERNAL "") + return() + endif() + + # If no variable is specified, log it instead + if(NOT ${FIND_LIB_QUIET}) + message( + ${HIGHLIGHTED_STATUS} + "find_external_library: ${name} was not found. ${missing_components}." + ) + endif() + endif() +endfunction() diff --git a/build-support/custom-modules/ns3-hidden-settings.cmake b/build-support/custom-modules/ns3-hidden-settings.cmake new file mode 100644 index 000000000..e10976f51 --- /dev/null +++ b/build-support/custom-modules/ns3-hidden-settings.cmake @@ -0,0 +1,49 @@ +# Copyright (c) 2023 Universidade de Brasília +# +# 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: Gabriel Ferreira + +# Set INT128 as the default option for INT64X64 and register alternative +# implementations +set(NS3_INT64X64 "INT128" CACHE STRING "Int64x64 implementation") +set_property(CACHE NS3_INT64X64 PROPERTY STRINGS INT128 CAIRO DOUBLE) + +# Purposefully hidden options: + +# For ease of use, export all libraries and include directories to ns-3 module +# consumers by default +option(NS3_REEXPORT_THIRD_PARTY_LIBRARIES "Export all third-party libraries +and include directories to ns-3 module consumers" ON +) + +# Since we can't really do that safely from the CMake side +option(NS3_ENABLE_SUDO + "Set executables ownership to root and enable the SUID flag" OFF +) + +# A flag that controls some aspects related to pip packaging +option(NS3_PIP_PACKAGING "Control aspects related to pip wheel packaging" OFF) + +# fPIC (position-independent code) and fPIE (position-independent executable) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) + +# Do not create a file-level dependency with shared libraries reducing +# unnecessary relinking +set(CMAKE_LINK_DEPENDS_NO_SHARED TRUE) + +# Honor CMAKE_CXX_STANDARD in check_cxx_source_compiles +# https://cmake.org/cmake/help/latest/policy/CMP0067.html +cmake_policy(SET CMP0066 NEW) +cmake_policy(SET CMP0067 NEW) diff --git a/build-support/custom-modules/ns3-lock.cmake b/build-support/custom-modules/ns3-lock.cmake index d1eb8caad..e28a493e3 100644 --- a/build-support/custom-modules/ns3-lock.cmake +++ b/build-support/custom-modules/ns3-lock.cmake @@ -76,7 +76,6 @@ function(write_lock) string(REPLACE ";" "', '" PATH_LIST "${PATH_LIST}") string(APPEND lock_contents "NS3_MODULE_PATH = ['${PATH_LIST}']\n") - cache_cmake_flag(ENABLE_REALTIME "ENABLE_REAL_TIME" lock_contents) cache_cmake_flag(ENABLE_EXAMPLES "ENABLE_EXAMPLES" lock_contents) cache_cmake_flag(ENABLE_TESTS "ENABLE_TESTS" lock_contents) cache_cmake_flag(NS3_OPENFLOW "ENABLE_OPENFLOW" lock_contents) diff --git a/build-support/custom-modules/ns3-module-macros.cmake b/build-support/custom-modules/ns3-module-macros.cmake index 82f5d0590..e0b3e41e5 100644 --- a/build-support/custom-modules/ns3-module-macros.cmake +++ b/build-support/custom-modules/ns3-module-macros.cmake @@ -15,6 +15,80 @@ # # Author: Gabriel Ferreira +add_custom_target(copy_all_headers) +function(copy_headers_before_building_lib libname outputdir headers visibility) + foreach(header ${headers}) + # Copy header to output directory on changes -> too darn slow + # configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${header} ${outputdir}/ + # COPYONLY) + + get_filename_component( + header_name ${CMAKE_CURRENT_SOURCE_DIR}/${header} NAME + ) + + # If output directory does not exist, create it + if(NOT (EXISTS ${outputdir})) + file(MAKE_DIRECTORY ${outputdir}) + endif() + + # If header already exists, skip symlinking/stub header creation + if(EXISTS ${outputdir}/${header_name}) + continue() + endif() + + # Create a stub header in the output directory, including the real header + # inside their respective module + get_filename_component( + ABSOLUTE_HEADER_PATH "${CMAKE_CURRENT_SOURCE_DIR}/${header}" ABSOLUTE + ) + file(WRITE ${outputdir}/${header_name} + "#include \"${ABSOLUTE_HEADER_PATH}\"\n" + ) + endforeach() +endfunction(copy_headers_before_building_lib) + +function(remove_lib_prefix prefixed_library library) + # Check if there is a lib prefix + string(FIND "${prefixed_library}" "lib" lib_pos) + + # If there is a lib prefix, try to remove it + if(${lib_pos} EQUAL 0) + # Check if we still have something remaining after removing the "lib" prefix + string(LENGTH ${prefixed_library} len) + if(${len} LESS 4) + message(FATAL_ERROR "Invalid library name: ${prefixed_library}") + endif() + + # Remove lib prefix from module name (e.g. libcore -> core) + string(SUBSTRING "${prefixed_library}" 3 -1 unprefixed_library) + else() + set(unprefixed_library ${prefixed_library}) + endif() + + # Save the unprefixed library name to the parent scope + set(${library} ${unprefixed_library} PARENT_SCOPE) +endfunction() + +function(check_for_missing_libraries output_variable_name libraries) + set(missing_dependencies) + foreach(lib ${libraries}) + # skip check for ns-3 modules if its a path to a library + if(EXISTS ${lib}) + continue() + endif() + + # check if the example depends on disabled modules + remove_lib_prefix("${lib}" lib) + + # Check if the module exists in the ns-3 modules list or if it is a + # 3rd-party library + if(NOT (${lib} IN_LIST ns3-all-enabled-modules)) + list(APPEND missing_dependencies ${lib}) + endif() + endforeach() + set(${output_variable_name} ${missing_dependencies} PARENT_SCOPE) +endfunction() + # cmake-format: off # # This macro processes a ns-3 module @@ -94,6 +168,7 @@ function(build_lib) add_library(ns3::${lib${BLIB_LIBNAME}} ALIAS ${lib${BLIB_LIBNAME}}) # Associate public headers with library for installation purposes + set(config_headers) if("${BLIB_LIBNAME}" STREQUAL "core") set(config_headers ${CMAKE_HEADER_OUTPUT_DIRECTORY}/config-store-config.h ${CMAKE_HEADER_OUTPUT_DIRECTORY}/core-config.h @@ -104,9 +179,7 @@ function(build_lib) ) endif() - if((NOT FILESYSTEM_LIBRARY_IS_LINKED) OR (${GCC} AND ${GCC8})) - # The GCC8 alternative is necessary since when installed alongside newer - # releases, the incorrect shared library can end up being linked. + if(NOT FILESYSTEM_LIBRARY_IS_LINKED) list(APPEND BLIB_LIBRARIES_TO_LINK -lstdc++fs) endif() @@ -225,17 +298,9 @@ function(build_lib) ) if(NOT ${XCODE}) - # Since linking libraries to object libraries in not allowed in older CMake - # releases, we need to import each of their include directories. Otherwise, - # include directories won't be properly propagated - set(temp) - foreach(target ${ns_libraries_to_link}) - list(APPEND temp - "$" - ) - endforeach() - target_include_directories(${lib${BLIB_LIBNAME}}-obj PRIVATE ${temp}) - unset(temp) + target_link_libraries( + ${lib${BLIB_LIBNAME}}-obj PRIVATE ${ns_libraries_to_link} + ) endif() # set output name of library @@ -468,8 +533,9 @@ function(build_lib_example) if((NOT missing_dependencies) AND ${filtered_in}) # Convert boolean into text to forward argument + set(IGNORE_PCH) if(${BLIB_EXAMPLE_IGNORE_PCH}) - set(IGNORE_PCH IGNORE_PCH) + set(IGNORE_PCH "IGNORE_PCH") endif() # Create executable with sources and headers # cmake-format: off @@ -479,7 +545,7 @@ function(build_lib_example) HEADER_FILES ${BLIB_EXAMPLE_HEADER_FILES} LIBRARIES_TO_LINK ${lib${BLIB_LIBNAME}} ${BLIB_EXAMPLE_LIBRARIES_TO_LINK} - ${optional_visualizer_lib} + ${ns3-optional-visualizer-lib} EXECUTABLE_DIRECTORY_PATH ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${FOLDER}/ ${IGNORE_PCH} ) diff --git a/build-support/custom-modules/ns3-ns3rc-parser.cmake b/build-support/custom-modules/ns3-ns3rc-parser.cmake new file mode 100644 index 000000000..c79d5016f --- /dev/null +++ b/build-support/custom-modules/ns3-ns3rc-parser.cmake @@ -0,0 +1,112 @@ +# Copyright (c) 2023 Universidade de Brasília +# +# 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: Gabriel Ferreira + +# Parse .ns3rc +macro(parse_ns3rc enabled_modules disabled_modules examples_enabled + tests_enabled +) + # Try to find .ns3rc + disable_cmake_warnings() + find_file(NS3RC .ns3rc PATHS /etc $ENV{HOME} $ENV{USERPROFILE} + ${PROJECT_SOURCE_DIR} NO_CACHE + ) + enable_cmake_warnings() + + # Set variables with default values (all modules, no examples nor tests) + set(${enabled_modules} "") + set(${disabled_modules} "") + set(${examples_enabled} "FALSE") + set(${tests_enabled} "FALSE") + + if(NOT (${NS3RC} STREQUAL "NS3RC-NOTFOUND")) + message(${HIGHLIGHTED_STATUS} + "Configuration file .ns3rc being used : ${NS3RC}" + ) + file(READ ${NS3RC} ns3rc_contents) + # Check if ns3rc file is CMake or Python based and act accordingly + if(ns3rc_contents MATCHES "ns3rc_*") + include(${NS3RC}) + else() + parse_python_ns3rc( + "${ns3rc_contents}" ${enabled_modules} ${examples_enabled} + ${tests_enabled} ${NS3RC} + ) + endif() + endif() +endmacro(parse_ns3rc) + +function(parse_python_ns3rc ns3rc_contents enabled_modules examples_enabled + tests_enabled ns3rc_location +) + # Save .ns3rc backup + file(WRITE ${ns3rc_location}.backup ${ns3rc_contents}) + + # Match modules_enabled list + if(ns3rc_contents MATCHES "modules_enabled.*\\[(.*).*\\]") + set(${enabled_modules} ${CMAKE_MATCH_1}) + if(${enabled_modules} MATCHES "all_modules") + # If all modules, just clean the filter and all modules will get built by + # default + set(${enabled_modules}) + else() + # If modules are listed, remove quotes and replace commas with semicolons + # transforming a string into a cmake list + string(REPLACE "," ";" ${enabled_modules} "${${enabled_modules}}") + string(REPLACE "'" "" ${enabled_modules} "${${enabled_modules}}") + string(REPLACE "\"" "" ${enabled_modules} "${${enabled_modules}}") + string(REPLACE " " "" ${enabled_modules} "${${enabled_modules}}") + string(REPLACE "\n" ";" ${enabled_modules} "${${enabled_modules}}") + list(SORT ${enabled_modules}) + + # Remove possibly empty entry + list(REMOVE_ITEM ${enabled_modules} "") + foreach(element ${${enabled_modules}}) + # Inspect each element for comments + if(${element} MATCHES "#.*") + list(REMOVE_ITEM ${enabled_modules} ${element}) + endif() + endforeach() + endif() + endif() + + string(REPLACE "True" "ON" ns3rc_contents ${ns3rc_contents}) + string(REPLACE "False" "OFF" ns3rc_contents ${ns3rc_contents}) + + # Match examples_enabled flag + if(ns3rc_contents MATCHES "examples_enabled = (ON|OFF)") + set(${examples_enabled} ${CMAKE_MATCH_1}) + endif() + + # Match tests_enabled flag + if(ns3rc_contents MATCHES "tests_enabled = (ON|OFF)") + set(${tests_enabled} ${CMAKE_MATCH_1}) + endif() + + # Save variables to parent scope + set(${enabled_modules} "${${enabled_modules}}" PARENT_SCOPE) + set(${examples_enabled} "${${examples_enabled}}" PARENT_SCOPE) + set(${tests_enabled} "${${tests_enabled}}" PARENT_SCOPE) + + # Save updated .ns3rc file + message( + ${HIGHLIGHTED_STATUS} + "The python-based .ns3rc file format is deprecated and was updated to the CMake format" + ) + configure_file( + ${PROJECT_SOURCE_DIR}/build-support/.ns3rc-template ${ns3rc_location} @ONLY + ) +endfunction(parse_python_ns3rc) diff --git a/build-support/custom-modules/ns3-output-directory.cmake b/build-support/custom-modules/ns3-output-directory.cmake new file mode 100644 index 000000000..1514b227a --- /dev/null +++ b/build-support/custom-modules/ns3-output-directory.cmake @@ -0,0 +1,82 @@ +# Copyright (c) 2023 Universidade de Brasília +# +# 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: Gabriel Ferreira + +# This is where we define where executables, libraries and headers will end up + +if("${NS3_OUTPUT_DIRECTORY}" STREQUAL "") + message(STATUS "Using default output directory ${PROJECT_SOURCE_DIR}/build") + set(CMAKE_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/build) # default output + # folder +else() + # Check if NS3_OUTPUT_DIRECTORY is a relative path + set(absolute_ns3_output_directory "${NS3_OUTPUT_DIRECTORY}") + if(NOT IS_ABSOLUTE ${NS3_OUTPUT_DIRECTORY}) + set(absolute_ns3_output_directory + "${PROJECT_SOURCE_DIR}/${NS3_OUTPUT_DIRECTORY}" + ) + endif() + + # Transform backward slash into forward slash Not the best way to do it since + # \ is a scape thing and can be used before whitespaces + string(REPLACE "\\" "/" absolute_ns3_output_directory + "${absolute_ns3_output_directory}" + ) + + if(NOT (EXISTS ${absolute_ns3_output_directory})) + message( + STATUS + "User-defined output directory \"${NS3_OUTPUT_DIRECTORY}\" doesn't exist. Trying to create it" + ) + file(MAKE_DIRECTORY ${absolute_ns3_output_directory}) + if(NOT (EXISTS ${absolute_ns3_output_directory})) + message( + FATAL_ERROR + "User-defined output directory \"${absolute_ns3_output_directory}\" could not be created. " + "Try changing the value of NS3_OUTPUT_DIRECTORY" + ) + endif() + + # If this directory is not inside the ns-3-dev folder, alert users tests may + # break + if(NOT ("${absolute_ns3_output_directory}" MATCHES "${PROJECT_SOURCE_DIR}")) + message( + WARNING + "User-defined output directory \"${absolute_ns3_output_directory}\" is outside " + " of the ns-3 directory ${PROJECT_SOURCE_DIR}, which will break some tests" + ) + endif() + endif() + message( + STATUS + "User-defined output directory \"${absolute_ns3_output_directory}\" will be used" + ) + set(CMAKE_OUTPUT_DIRECTORY ${absolute_ns3_output_directory}) +endif() + +set(libdir "lib") +if(${CMAKE_INSTALL_LIBDIR} MATCHES "lib64") + set(libdir "lib64") +endif() + +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_OUTPUT_DIRECTORY}/${libdir}) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_OUTPUT_DIRECTORY}/${libdir}) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_OUTPUT_DIRECTORY}) +set(CMAKE_HEADER_OUTPUT_DIRECTORY ${CMAKE_OUTPUT_DIRECTORY}/include/ns3) +set(THIRD_PARTY_DIRECTORY ${PROJECT_SOURCE_DIR}/3rd-party) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +link_directories(${CMAKE_OUTPUT_DIRECTORY}/${libdir}) +file(MAKE_DIRECTORY ${CMAKE_OUTPUT_DIRECTORY}) diff --git a/build-support/custom-modules/ns3-platform-support.cmake b/build-support/custom-modules/ns3-platform-support.cmake new file mode 100644 index 000000000..bc83344e5 --- /dev/null +++ b/build-support/custom-modules/ns3-platform-support.cmake @@ -0,0 +1,81 @@ +# Copyright (c) 2023 Universidade de Brasília +# +# 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: Gabriel Ferreira + +# This is where we check for platform specifics + +# WSLv1 doesn't support tap features +if(EXISTS "/proc/version") + file(READ "/proc/version" CMAKE_LINUX_DISTRO) + string(FIND "${CMAKE_LINUX_DISTRO}" "Microsoft" res) + if(res EQUAL -1) + set(WSLv1 False) + else() + set(WSLv1 True) + endif() +endif() + +# Set Linux flag if on Linux +if(UNIX AND NOT APPLE) + set(LINUX TRUE) + add_definitions(-D__LINUX__) +endif() + +if(APPLE) + add_definitions(-D__APPLE__) + # cmake-format: off + # Configure find_program to search for AppBundles only if programs are not found in PATH. + # This prevents Doxywizard from being launched when the Doxygen.app is installed. + # https://gitlab.kitware.com/cmake/cmake/-/blob/master/Modules/FindDoxygen.cmake + # cmake-format: on + set(CMAKE_FIND_APPBUNDLE "LAST") +endif() + +if(WIN32) + set(NS3_PRECOMPILE_HEADERS OFF + CACHE BOOL "Precompile module headers to speed up compilation" FORCE + ) + + # For whatever reason getting M_PI and other math.h definitions from cmath + # requires this definition + # https://docs.microsoft.com/en-us/cpp/c-runtime-library/math-constants?view=vs-2019 + add_definitions(/D_USE_MATH_DEFINES) +endif() + +set(cat_command cat) + +if(CMAKE_XCODE_BUILD_SYSTEM) + set(XCODE True) +else() + set(XCODE False) +endif() + +if(${XCODE}) + # Is that so hard not to break people's CI, AAPL? Why would you output the + # targets to a Debug/Release subfolder? Why? + foreach(OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES}) + string(TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} + ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} + ) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_${OUTPUTCONFIG} + ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} + ) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${OUTPUTCONFIG} + ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY} + ) + endforeach() +endif() diff --git a/build-support/custom-modules/ns3-vcpkg-hunter.cmake b/build-support/custom-modules/ns3-vcpkg-hunter.cmake index db8acdc75..093d5eb94 100644 --- a/build-support/custom-modules/ns3-vcpkg-hunter.cmake +++ b/build-support/custom-modules/ns3-vcpkg-hunter.cmake @@ -73,7 +73,7 @@ function(setup_vcpkg) ) endif() - if(${MSVC}) + if(DEFINED MSVC) message(FATAL_ERROR "vcpkg: Visual Studio is unsupported") else() # Check if required packages are installed (unzip curl tar) @@ -134,10 +134,12 @@ function(setup_vcpkg) execute_process(COMMAND chmod +x ${VCPKG_DIR}/${VCPKG_EXEC}) endif() + disable_cmake_warnings() set(CMAKE_PREFIX_PATH "${VCPKG_DIR}/installed/${VCPKG_TRIPLET}/;${CMAKE_PREFIX_PATH}" PARENT_SCOPE ) + enable_cmake_warnings() # Install packages in manifest mode if(EXISTS ${VCPKG_MANIFEST}) @@ -195,4 +197,6 @@ endfunction() if(${NS3_VCPKG}) setup_vcpkg() + include_directories(${VCPKG_DIR}/installed/${VCPKG_TRIPLET}/include) + link_directories(${VCPKG_DIR}/installed/${VCPKG_TRIPLET}/lib) endif() diff --git a/build-support/macros-and-definitions.cmake b/build-support/macros-and-definitions.cmake index 490f14b08..0147392e4 100644 --- a/build-support/macros-and-definitions.cmake +++ b/build-support/macros-and-definitions.cmake @@ -18,296 +18,57 @@ # Export compile time variable setting the directory to the NS3 root folder add_definitions(-DPROJECT_SOURCE_PATH="${PROJECT_SOURCE_DIR}") -# Set INT128 as the default option for INT64X64 and register alternative -# implementations -set(NS3_INT64X64 "INT128" CACHE STRING "Int64x64 implementation") -set_property(CACHE NS3_INT64X64 PROPERTY STRINGS INT128 CAIRO DOUBLE) - -# Purposefully hidden options: - -# for ease of use, export all libraries and include directories to ns-3 module -# consumers by default -option(NS3_REEXPORT_THIRD_PARTY_LIBRARIES "Export all third-party libraries -and include directories to ns-3 module consumers" ON +# Add custom and 3rd-part cmake modules to the path +list(APPEND CMAKE_MODULE_PATH + "${PROJECT_SOURCE_DIR}/build-support/custom-modules" ) +list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/build-support/3rd-party") -# since we can't really do that safely from the CMake side -option(NS3_ENABLE_SUDO - "Set executables ownership to root and enable the SUID flag" OFF -) +macro(disable_cmake_warnings) + set(CMAKE_SUPPRESS_DEVELOPER_WARNINGS 1 CACHE BOOL "" FORCE) +endmacro() -# a flag that controls some aspects related to pip packaging -option(NS3_PIP_PACKAGING "Control aspects related to pip wheel packaging" OFF) +macro(enable_cmake_warnings) + set(CMAKE_SUPPRESS_DEVELOPER_WARNINGS 0 CACHE BOOL "" FORCE) +endmacro() + +# Set options that are not really meant to be changed +include(ns3-hidden-settings) # Replace default CMake messages (logging) with custom colored messages as early # as possible -include(${PROJECT_SOURCE_DIR}/build-support/3rd-party/colored-messages.cmake) +include(colored-messages) -# WSLv1 doesn't support tap features -if(EXISTS "/proc/version") - file(READ "/proc/version" CMAKE_LINUX_DISTRO) - string(FIND "${CMAKE_LINUX_DISTRO}" "Microsoft" res) - if(res EQUAL -1) - set(WSLv1 False) - else() - set(WSLv1 True) - endif() -endif() - -# Set Linux flag if on Linux -if(UNIX AND NOT APPLE) - set(LINUX TRUE) - add_definitions(-D__LINUX__) -endif() - -if(APPLE) - add_definitions(-D__APPLE__) - # cmake-format: off - # Configure find_program to search for AppBundles only if programs are not found in PATH. - # This prevents Doxywizard from being launched when the Doxygen.app is installed. - # https://gitlab.kitware.com/cmake/cmake/-/blob/master/Modules/FindDoxygen.cmake - # cmake-format: on - set(CMAKE_FIND_APPBUNDLE "LAST") -endif() - -if(WIN32) - set(NS3_PRECOMPILE_HEADERS OFF - CACHE BOOL "Precompile module headers to speed up compilation" FORCE - ) - - # For whatever reason getting M_PI and other math.h definitions from cmath - # requires this definition - # https://docs.microsoft.com/en-us/cpp/c-runtime-library/math-constants?view=vs-2019 - add_definitions(/D_USE_MATH_DEFINES) -endif() - -set(cat_command cat) - -if(CMAKE_XCODE_BUILD_SYSTEM) - set(XCODE True) -else() - set(XCODE False) -endif() - -# Check the number of threads -include(ProcessorCount) -ProcessorCount(NumThreads) - -# Output folders -if("${NS3_OUTPUT_DIRECTORY}" STREQUAL "") - message(STATUS "Using default output directory ${PROJECT_SOURCE_DIR}/build") - set(CMAKE_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/build) # default output - # folder -else() - # Check if NS3_OUTPUT_DIRECTORY is a relative path - set(absolute_ns3_output_directory "${NS3_OUTPUT_DIRECTORY}") - if(NOT IS_ABSOLUTE ${NS3_OUTPUT_DIRECTORY}) - set(absolute_ns3_output_directory - "${PROJECT_SOURCE_DIR}/${NS3_OUTPUT_DIRECTORY}" - ) - endif() - - # Transform backward slash into forward slash Not the best way to do it since - # \ is a scape thing and can be used before whitespaces - string(REPLACE "\\" "/" absolute_ns3_output_directory - "${absolute_ns3_output_directory}" - ) - - if(NOT (EXISTS ${absolute_ns3_output_directory})) - message( - STATUS - "User-defined output directory \"${NS3_OUTPUT_DIRECTORY}\" doesn't exist. Trying to create it" - ) - file(MAKE_DIRECTORY ${absolute_ns3_output_directory}) - if(NOT (EXISTS ${absolute_ns3_output_directory})) - message( - FATAL_ERROR - "User-defined output directory \"${absolute_ns3_output_directory}\" could not be created. " - "Try changing the value of NS3_OUTPUT_DIRECTORY" - ) - endif() - - # If this directory is not inside the ns-3-dev folder, alert users tests may - # break - if(NOT ("${absolute_ns3_output_directory}" MATCHES "${PROJECT_SOURCE_DIR}")) - message( - WARNING - "User-defined output directory \"${absolute_ns3_output_directory}\" is outside " - " of the ns-3 directory ${PROJECT_SOURCE_DIR}, which will break some tests" - ) - endif() - endif() - message( - STATUS - "User-defined output directory \"${absolute_ns3_output_directory}\" will be used" - ) - set(CMAKE_OUTPUT_DIRECTORY ${absolute_ns3_output_directory}) -endif() -set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_OUTPUT_DIRECTORY}/lib) -set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_OUTPUT_DIRECTORY}/lib) -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_OUTPUT_DIRECTORY}) -set(CMAKE_HEADER_OUTPUT_DIRECTORY ${CMAKE_OUTPUT_DIRECTORY}/include/ns3) -set(THIRD_PARTY_DIRECTORY ${PROJECT_SOURCE_DIR}/3rd-party) -set(CMAKE_EXPORT_COMPILE_COMMANDS ON) -link_directories(${CMAKE_OUTPUT_DIRECTORY}/lib) -file(MAKE_DIRECTORY ${CMAKE_OUTPUT_DIRECTORY}) - -# Get installation folder default values for each platform and include package -# configuration macro +# Get installation folder default values include(GNUInstallDirs) -include(build-support/custom-modules/ns3-cmake-package.cmake) -# Set RPATH not too need LD_LIBRARY_PATH after installing -set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib:$ORIGIN/:$ORIGIN/../lib") +# Define output directories +include(ns3-output-directory) -# Add the 64 suffix to the library path when manually requested with the -# -DNS3_USE_LIB64=ON flag. May be necessary depending on the target platform. -# This is used to properly build the manylinux pip wheel. -if(${NS3_USE_LIB64}) - link_directories(${CMAKE_OUTPUT_DIRECTORY}/lib64) - set(CMAKE_INSTALL_RPATH - "${CMAKE_INSTALL_RPATH}:${CMAKE_INSTALL_PREFIX}/lib64:$ORIGIN/:$ORIGIN/../lib64" - ) -endif() +# Configure packaging related settings +include(ns3-cmake-package) -# cmake-format: off -# You are a wizard, Harry! -# source: https://gitlab.kitware.com/cmake/community/-/wikis/doc/cmake/RPATH-handling -# cmake-format: on -set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) +# Windows, Linux and Mac related checks +include(ns3-platform-support) -if(${XCODE}) - # Is that so hard not to break people's CI, AAPL? Why would you output the - # targets to a Debug/Release subfolder? Why? - foreach(OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES}) - string(TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG) - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} - ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} - ) - set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_${OUTPUTCONFIG} - ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} - ) - set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${OUTPUTCONFIG} - ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY} - ) - endforeach() -endif() +# Perform compiler and linker checks +include(ns3-compiler-and-linker-support) -# fPIC (position-independent code) and fPIE (position-independent executable) -set(CMAKE_POSITION_INDEPENDENT_CODE ON) +# Include CMake file with common find_program HINTS +include(find-program-hints) -# do not create a file-level dependency with shared libraries reducing -# unnecessary relinking -set(CMAKE_LINK_DEPENDS_NO_SHARED TRUE) +# Custom find_package alternative +include(ns3-find-external-library) -# Identify compiler and check version -set(below_minimum_msg "compiler is below the minimum required version") -set(CLANG FALSE) -if("${CMAKE_CXX_COMPILER_ID}" MATCHES "AppleClang") - if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS ${AppleClang_MinVersion}) - message( - FATAL_ERROR - "Apple Clang ${CMAKE_CXX_COMPILER_VERSION} ${below_minimum_msg} ${AppleClang_MinVersion}" - ) - endif() - set(CLANG TRUE) -endif() - -if((NOT CLANG) AND ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")) - if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS ${Clang_MinVersion}) - message( - FATAL_ERROR - "Clang ${CMAKE_CXX_COMPILER_VERSION} ${below_minimum_msg} ${Clang_MinVersion}" - ) - endif() - set(CLANG TRUE) -endif() - -if(CLANG) - if(${NS3_COLORED_OUTPUT} OR "$ENV{CLICOLOR}") - add_definitions(-fcolor-diagnostics) # colorize clang++ output - endif() -endif() - -set(GCC FALSE) -set(GCC8 FALSE) -if("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") - if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS ${GNU_MinVersion}) - message( - FATAL_ERROR - "GNU ${CMAKE_CXX_COMPILER_VERSION} ${below_minimum_msg} ${GNU_MinVersion}" - ) - endif() - if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "9.0.0") - # This block is used to identify if GCC8 is being used. In this case, we - # want to explicitly link stdc++fs, which is done in - # ns3-module-macros.cmake. - set(GCC8 TRUE) - endif() - set(GCC TRUE) - add_definitions(-fno-semantic-interposition) - if(${NS3_COLORED_OUTPUT} OR "$ENV{CLICOLOR}") - add_definitions(-fdiagnostics-color=always) # colorize g++ output - endif() -endif() -unset(below_minimum_msg) +# Custom check_deps to search for packages, executables and python dependencies +include(ns3-check-dependencies) # Set compiler options and get command to force unused function linkage (useful # for libraries) -set(CXX_UNSUPPORTED_STANDARDS 98 11 14) -set(CMAKE_CXX_STANDARD_MINIMUM 17) +set(CXX_UNSUPPORTED_STANDARDS 98 11 14 17) +set(CMAKE_CXX_STANDARD_MINIMUM 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) -set(LIB_AS_NEEDED_PRE) -set(LIB_AS_NEEDED_POST) -set(STATIC_LINK_FLAGS -static -static-libstdc++ -static-libgcc) -if(${GCC} AND NOT APPLE) - # using GCC - set(LIB_AS_NEEDED_PRE -Wl,--no-as-needed) - set(LIB_AS_NEEDED_POST -Wl,--as-needed) - set(LIB_AS_NEEDED_PRE_STATIC -Wl,--whole-archive,-Bstatic) - set(LIB_AS_NEEDED_POST_STATIC -Wl,--no-whole-archive) - set(LIB_AS_NEEDED_POST_STATIC_DYN -Wl,-Bdynamic,--no-whole-archive) -endif() - -if(${CLANG} AND APPLE) - # using Clang set(LIB_AS_NEEDED_PRE -all_load) - set(LIB_AS_NEEDED_POST) - set(LIB_AS_NEEDED_PRE_STATIC -Wl,-all_load) - set(STATIC_LINK_FLAGS) -endif() - -if(${NS3_FAST_LINKERS}) - # Search for faster linkers mold and lld, and use them if available - mark_as_advanced(MOLD LLD) - find_program(MOLD mold) - find_program(LLD ld.lld) - - # USING_FAST_LINKER will be defined if a fast linker is being used and its - # content will correspond to the fast linker name - - # Mold support was added in GCC 12.1.0 - if(NOT USING_FAST_LINKER - AND NOT (${MOLD} STREQUAL "MOLD-NOTFOUND") - AND LINUX - AND ${GCC} - AND (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 12.1.0) - ) - set(USING_FAST_LINKER MOLD) - add_link_options("-fuse-ld=mold") - endif() - - if(NOT USING_FAST_LINKER AND NOT (${LLD} STREQUAL "LLD-NOTFOUND") - AND (${GCC} OR ${CLANG}) - ) - set(USING_FAST_LINKER LLD) - add_link_options("-fuse-ld=lld") - if(WIN32) - # Clear unsupported linker flags on Windows - set(LIB_AS_NEEDED_PRE) - endif() - endif() -endif() # Include CMake files used for compiler checks include(CheckIncludeFile) # Used to check a single C header at a time @@ -315,6 +76,10 @@ include(CheckIncludeFileCXX) # Used to check a single C++ header at a time include(CheckIncludeFiles) # Used to check multiple headers at once include(CheckFunctionExists) +# Check the number of threads +include(ProcessorCount) +ProcessorCount(NumThreads) + macro(SUBDIRLIST result curdir) file(GLOB children RELATIVE ${curdir} ${curdir}/*) set(dirlist "") @@ -334,16 +99,25 @@ macro(clear_global_cached_variables) # clear cache variables unset(build_profile CACHE) unset(build_profile_suffix CACHE) - unset(lib-ns3-static-objs CACHE) - unset(ns3-contrib-libs CACHE) - unset(ns3-example-folders CACHE) - unset(ns3-execs CACHE) - unset(ns3-execs-clean CACHE) - unset(ns3-execs-py CACHE) - unset(ns3-external-libs CACHE) - unset(ns3-headers-to-module-map CACHE) - unset(ns3-libs CACHE) - unset(ns3-libs-tests CACHE) + set(lib-ns3-static-objs + "" + CACHE + INTERNAL + "list of object files from module used by NS3_STATIC and NS3_MONOLIB" + ) + set(ns3-contrib-libs "" CACHE INTERNAL "list of processed contrib modules") + set(ns3-example-folders "" CACHE INTERNAL "list of example folders") + set(ns3-execs "" CACHE INTERNAL "list of c++ executables") + set(ns3-execs-clean "" CACHE INTERNAL "list of c++ executables") + set(ns3-execs-py "" CACHE INTERNAL "list of python scripts") + set(ns3-external-libs "" + CACHE INTERNAL + "list of non-ns libraries to link to NS3_STATIC and NS3_MONOLIB" + ) + set(ns3-libs "" CACHE INTERNAL "list of processed upstream modules") + set(ns3-libs-tests "" CACHE INTERNAL "list of test libraries") + set(ns3-optional-visualizer-lib "" CACHE INTERNAL "visualizer library name") + mark_as_advanced( build_profile build_profile_suffix @@ -354,45 +128,12 @@ macro(clear_global_cached_variables) ns3-execs-clean ns3-execs-py ns3-external-libs - ns3-headers-to-module-map ns3-libs ns3-libs-tests + ns3-optional-visualizer-lib ) endmacro() -# Include CMake file with common find_program HINTS -include(build-support/3rd-party/find-program-hints.cmake) - -# function used to search for package and program dependencies than store list -# of missing dependencies in the list whose name is stored in missing_deps -function(check_deps package_deps program_deps missing_deps) - set(local_missing_deps) - # Search for package dependencies - foreach(package ${package_deps}) - find_package(${package}) - if(NOT ${${package}_FOUND}) - list(APPEND local_missing_deps ${package}) - endif() - endforeach() - - # And for program dependencies - foreach(program ${program_deps}) - # CMake likes to cache find_* to speed things up, so we can't reuse names - # here or it won't check other dependencies - string(TOUPPER ${program} upper_${program}) - mark_as_advanced(${upper_${program}}) - find_program( - ${upper_${program}} ${program} HINTS ${3RD_PARTY_FIND_PROGRAM_HINTS} - ) - if("${${upper_${program}}}" STREQUAL "${upper_${program}}-NOTFOUND") - list(APPEND local_missing_deps ${program}) - endif() - endforeach() - - # Store list of missing dependencies in the parent scope - set(${missing_deps} ${local_missing_deps} PARENT_SCOPE) -endfunction() - # process all options passed in main cmakeLists macro(process_options) clear_global_cached_variables() @@ -466,7 +207,7 @@ macro(process_options) # Set warning level and warning as errors if(${NS3_WARNINGS}) - if(MSVC) + if(DEFINED MSVC) add_compile_options(/W3) # /W4 = -Wall + -Wextra if(${NS3_WARNINGS_AS_ERRORS}) add_compile_options(/WX) @@ -479,7 +220,7 @@ macro(process_options) endif() endif() - include(build-support/custom-modules/ns3-versioning.cmake) + include(ns3-versioning) set(ENABLE_BUILD_VERSION False) configure_embedded_version() @@ -515,18 +256,6 @@ macro(process_options) if("${CLANG_TIDY}" STREQUAL "CLANG_TIDY-NOTFOUND") message(FATAL_ERROR "Clang-tidy was not found") else() - if((${CMAKE_VERSION} VERSION_LESS "3.12.0") AND ${NS3_CCACHE} - AND (NOT ("${CCACHE}" STREQUAL "CCACHE-NOTFOUND")) - ) - # CMake <3.12 puts CMAKE_CXX_COMPILER_LAUNCHER in the incorrect place - # and CCache ends up being unable to cache anything if calling - # clang-tidy https://gitlab.kitware.com/cmake/cmake/-/issues/18266 - message( - FATAL_ERROR - "The current CMake ${CMAKE_VERSION} won't ccache objects correctly when running with clang-tidy." - "Update CMake to at least version 3.12, or disable either ccache or clang-tidy to continue." - ) - endif() set(CMAKE_CXX_CLANG_TIDY "${CLANG_TIDY}") endif() else() @@ -596,12 +325,23 @@ macro(process_options) ${PROJECT_SOURCE_DIR}/build-support/cmake-format-modules.yaml -i ${MODULES_CMAKE_FILES} ) + add_custom_target( + cmake-format-check + COMMAND + ${CMAKE_FORMAT_PROGRAM} -c + ${PROJECT_SOURCE_DIR}/build-support/cmake-format.yaml --check + ${INTERNAL_CMAKE_FILES} + COMMAND + ${CMAKE_FORMAT_PROGRAM} -c + ${PROJECT_SOURCE_DIR}/build-support/cmake-format-modules.yaml --check + ${MODULES_CMAKE_FILES} + ) unset(MODULES_CMAKE_FILES) unset(INTERNAL_CMAKE_FILES) endif() # If the user has not set a CXX standard version, assume the minimum - if(NOT "${CMAKE_CXX_STANDARD}") + if(NOT (DEFINED CMAKE_CXX_STANDARD)) set(CMAKE_CXX_STANDARD ${CMAKE_CXX_STANDARD_MINIMUM}) endif() @@ -615,14 +355,9 @@ macro(process_options) ) endif() - # Honor CMAKE_CXX_STANDARD in check_cxx_source_compiles - # https://cmake.org/cmake/help/latest/policy/CMP0067.html - cmake_policy(SET CMP0066 NEW) - cmake_policy(SET CMP0067 NEW) - # After setting the correct CXX version, we can proceed to check for compiler # workarounds - include(build-support/custom-modules/ns3-compiler-workarounds.cmake) + include(ns3-compiler-workarounds) if(${NS3_DES_METRICS}) add_definitions(-DENABLE_DES_METRICS) @@ -729,12 +464,6 @@ macro(process_options) # Set common include folder (./build/include, where we find ns3/core-module.h) include_directories(${CMAKE_OUTPUT_DIRECTORY}/include) - # find required dependencies - list(APPEND CMAKE_MODULE_PATH - "${PROJECT_SOURCE_DIR}/build-support/custom-modules" - ) - list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/build-support/3rd-party") - # Include our package managers # cmake-format: off # Starting with a custom cmake file that provides a Hunter-like interface to vcpkg @@ -785,21 +514,24 @@ macro(process_options) # find_package(SQLite3 QUIET) # unsupported in CMake 3.10 We emulate the # behavior of find_package below find_external_library( - DEPENDENCY_NAME SQLite3 HEADER_NAME sqlite3.h LIBRARY_NAME sqlite3 + DEPENDENCY_NAME SQLite3 + HEADER_NAME sqlite3.h + LIBRARY_NAME sqlite3 + OUTPUT_VARIABLE "ENABLE_SQLITE_REASON" ) if(${SQLite3_FOUND}) set(ENABLE_SQLITE True) add_definitions(-DHAVE_SQLITE3) include_directories(${SQLite3_INCLUDE_DIRS}) - else() - message(${HIGHLIGHTED_STATUS} "SQLite was not found") endif() endif() set(ENABLE_EIGEN False) if(${NS3_EIGEN}) + disable_cmake_warnings() find_package(Eigen3 QUIET) + enable_cmake_warnings() if(${EIGEN3_FOUND}) set(ENABLE_EIGEN True) @@ -807,34 +539,32 @@ macro(process_options) add_definitions(-DEIGEN_MPL2_ONLY) include_directories(${EIGEN3_INCLUDE_DIR}) else() - message(${HIGHLIGHTED_STATUS} "Eigen was not found") + set(ENABLE_EIGEN_REASON "Eigen was not found") endif() endif() # GTK3 Don't search for it if you don't have it installed, as it take an # insane amount of time + set(GTK3_FOUND FALSE) if(${NS3_GTK3}) + disable_cmake_warnings() find_package(HarfBuzz QUIET) + enable_cmake_warnings() if(NOT ${HarfBuzz_FOUND}) - message(${HIGHLIGHTED_STATUS} - "Harfbuzz is required by GTK3 and was not found." - ) + set(GTK3_FOUND_REASON "Harfbuzz is required by GTK3 and was not found") else() - set(CMAKE_SUPPRESS_DEVELOPER_WARNINGS 1 CACHE BOOL "") + disable_cmake_warnings() find_package(GTK3 QUIET) - unset(CMAKE_SUPPRESS_DEVELOPER_WARNINGS CACHE) + enable_cmake_warnings() if(NOT ${GTK3_FOUND}) - message(${HIGHLIGHTED_STATUS} - "GTK3 was not found. Continuing without it." - ) + set(GTK3_FOUND_REASON "GTK3 was not found") else() if(${GTK3_VERSION} VERSION_LESS 3.22) set(GTK3_FOUND FALSE) - message(${HIGHLIGHTED_STATUS} - "GTK3 found with incompatible version ${GTK3_VERSION}" + set(GTK3_FOUND_REASON + "GTK3 found with incompatible version ${GTK3_VERSION}" ) else() - message(STATUS "GTK3 was found.") include_directories(${GTK3_INCLUDE_DIRS} ${HarfBuzz_INCLUDE_DIRS}) endif() endif() @@ -858,11 +588,8 @@ macro(process_options) else() find_package(LibXml2 QUIET) if(NOT ${LIBXML2_FOUND}) - message(${HIGHLIGHTED_STATUS} - "LibXML2 was not found. Continuing without it." - ) + set(LIBXML2_FOUND_REASON "LibXML2 was not found") else() - message(STATUS "LibXML2 was found.") add_definitions(-DHAVE_LIBXML2) include_directories(${LIBXML2_INCLUDE_DIR}) endif() @@ -878,31 +605,12 @@ macro(process_options) set(Python3_EXECUTABLE) set(Python3_FOUND FALSE) set(Python3_INCLUDE_DIRS) + set(Python3_Interpreter_FOUND FALSE) if(${NS3_PYTHON_BINDINGS}) - if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.12.0") - find_package(Python3 COMPONENTS Interpreter Development) - else() - # cmake-format: off - set(Python_ADDITIONAL_VERSIONS 3.6 3.7 3.8 3.9 3.10 3.11) - # cmake-format: on - find_package(PythonInterp) - find_package(PythonLibs) - - # Move deprecated results into the FindPython3 resulting variables - set(Python3_Interpreter_FOUND ${PYTHONINTERP_FOUND}) - set(Python3_Development_FOUND ${PYTHONLIBS_FOUND}) - if(${PYTHONINTERP_FOUND}) - set(Python3_EXECUTABLE ${PYTHON_EXECUTABLE}) - set(Python3_FOUND TRUE) - endif() - if(${PYTHONLIBS_FOUND}) - set(Python3_LIBRARIES ${PYTHON_LIBRARIES}) - set(Python3_INCLUDE_DIRS ${PYTHON_INCLUDE_DIRS}) - endif() - endif() + find_package(Python3 COMPONENTS Interpreter Development) else() # If Python was not set yet, use the version found by check_deps - check_deps("" "python3" python3_deps) + check_deps(python3_deps EXECUTABLES python3) if(python3_deps) message(FATAL_ERROR "Python3 was not found") else() @@ -964,7 +672,7 @@ macro(process_options) "macOS silicon detected -- see issue 930" ) else() - check_python_packages("cppyy" missing_packages) + check_deps(missing_packages PYTHON_PACKAGES cppyy) if(missing_packages) message( ${HIGHLIGHTED_STATUS} @@ -1072,9 +780,6 @@ macro(process_options) else() set(ENABLE_VISUALIZER_REASON "Python Bindings are disabled") endif() - if(ENABLE_VISUALIZER_REASON) - message(${HIGHLIGHTED_STATUS} "Visualizer: ${ENABLE_VISUALIZER_REASON}") - endif() endif() if(${NS3_COVERAGE} AND (NOT ${ENABLE_TESTS} OR NOT ${ENABLE_EXAMPLES})) @@ -1097,7 +802,7 @@ macro(process_options) DEPENDS all-test-targets ) if(${ENABLE_EXAMPLES}) - include(build-support/custom-modules/ns3-coverage.cmake) + include(ns3-coverage) endif() endif() @@ -1133,10 +838,11 @@ macro(process_options) set(CMAKE_REQUIRED_INCLUDES ${Boost_INCLUDE_DIRS}) endif() + set(GSL_FOUND FALSE) if(${NS3_GSL}) find_package(GSL QUIET) if(NOT ${GSL_FOUND}) - message(${HIGHLIGHTED_STATUS} "GSL was not found. Continuing without it.") + set(GSL_FOUND_REASON "GSL was not found") else() message(STATUS "GSL was found.") add_definitions(-DHAVE_GSL) @@ -1148,7 +854,7 @@ macro(process_options) # First we check for doxygen dependencies mark_as_advanced(DOXYGEN) - check_deps("" "doxygen;dot;dia;python3" doxygen_docs_missing_deps) + check_deps(doxygen_docs_missing_deps EXECUTABLES doxygen dot dia python3) if(doxygen_docs_missing_deps) message( ${HIGHLIGHTED_STATUS} @@ -1264,8 +970,8 @@ macro(process_options) # Check deps accepts a list of packages, list of programs and name of the # return variable check_deps( - "Sphinx" "epstopdf;pdflatex;latexmk;convert;dvipng" - sphinx_docs_missing_deps + sphinx_docs_missing_deps CMAKE_PACKAGES Sphinx + EXECUTABLES epstopdf pdflatex latexmk convert dvipng ) if(sphinx_docs_missing_deps) message( @@ -1441,6 +1147,7 @@ macro(process_options) if(APPLE OR WSLv1 OR WIN32) set(ENABLE_TAP OFF) set(ENABLE_EMU OFF) + set(ENABLE_FDNETDEV FALSE) list(REMOVE_ITEM libs_to_build fd-net-device) message( STATUS @@ -1481,9 +1188,10 @@ macro(process_options) set(lib${libname}-obj ${targetname}-obj CACHE INTERNAL "") endforeach() - unset(optional_visualizer_lib) if(${ENABLE_VISUALIZER} AND (visualizer IN_LIST libs_to_build)) - set(optional_visualizer_lib ${libvisualizer}) + set(ns3-optional-visualizer-lib "${libvisualizer}" + CACHE INTERNAL "visualizer library name" + ) endif() set(PRECOMPILE_HEADERS_ENABLED OFF) @@ -1610,254 +1318,40 @@ macro(process_options) endif() if(${NS3_FETCH_OPTIONAL_COMPONENTS}) - include( - build-support/custom-modules/ns3-fetch-optional-modules-dependencies.cmake - ) + include(ns3-fetch-optional-modules-dependencies) endif() endmacro() -function(set_runtime_outputdirectory target_name output_directory target_prefix) - # Prevent duplicate '/' in EXECUTABLE_DIRECTORY_PATH, since it gets translated - # to doubled underlines and will cause the ns3 script to fail - string(REPLACE "//" "/" output_directory "${output_directory}") - - set(ns3-exec-outputname ns${NS3_VER}-${target_name}${build_profile_suffix}) - set(ns3-execs "${output_directory}${ns3-exec-outputname};${ns3-execs}" - CACHE INTERNAL "list of c++ executables" - ) - set(ns3-execs-clean "${target_prefix}${target_name};${ns3-execs-clean}" - CACHE INTERNAL - "list of c++ executables without version prefix and build suffix" - ) - - set_target_properties( - ${target_prefix}${target_name} - PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${output_directory} - RUNTIME_OUTPUT_NAME ${ns3-exec-outputname} - ) - if(${XCODE}) - # Is that so hard not to break people's CI, AAPL?? Why would you output the - # targets to a Debug/Release subfolder? Why? - foreach(OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES}) - string(TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG) - set_target_properties( - ${target_prefix}${target_name} - PROPERTIES RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${output_directory} - RUNTIME_OUTPUT_NAME_${OUTPUTCONFIG} ${ns3-exec-outputname} - ) - endforeach(OUTPUTCONFIG CMAKE_CONFIGURATION_TYPES) - endif() - - if(${ENABLE_TESTS}) - add_dependencies(all-test-targets ${target_prefix}${target_name}) - # Create a CTest entry for each executable - if(WIN32) - # Windows require this workaround to make sure the DLL files are located - add_test( - NAME ctest-${target_prefix}${target_name} - COMMAND - ${CMAKE_COMMAND} -E env - "PATH=$ENV{PATH};${CMAKE_RUNTIME_OUTPUT_DIRECTORY};${CMAKE_LIBRARY_OUTPUT_DIRECTORY}" - ${ns3-exec-outputname} - WORKING_DIRECTORY ${output_directory} - ) +function(get_target_includes target output) + set(include_directories) + get_target_property(include_dirs ${target} INCLUDE_DIRECTORIES) + list(REMOVE_DUPLICATES include_dirs) + foreach(include_dir ${include_dirs}) + if(include_dir MATCHES "<") + # Skip CMake build and install interface includes + continue() else() - add_test(NAME ctest-${target_prefix}${target_name} - COMMAND ${ns3-exec-outputname} - WORKING_DIRECTORY ${output_directory} - ) - endif() - endif() - - if(${NS3_CLANG_TIMETRACE}) - add_dependencies(timeTraceReport ${target_prefix}${target_name}) - endif() -endfunction(set_runtime_outputdirectory) - -function(get_scratch_prefix prefix) - # /path/to/ns-3-dev/scratch/nested-subdir - set(temp ${CMAKE_CURRENT_SOURCE_DIR}) - # remove /path/to/ns-3-dev/ to get scratch/nested-subdir - string(REPLACE "${PROJECT_SOURCE_DIR}/" "" temp "${temp}") - # replace path separators with underlines - string(REPLACE "/" "_" temp "${temp}") - # save the prefix value to the passed variable - set(${prefix} ${temp}_ PARENT_SCOPE) -endfunction() - -function(build_exec) - # Argument parsing - set(options IGNORE_PCH STANDALONE) - set(oneValueArgs EXECNAME EXECNAME_PREFIX EXECUTABLE_DIRECTORY_PATH - INSTALL_DIRECTORY_PATH - ) - set(multiValueArgs SOURCE_FILES HEADER_FILES LIBRARIES_TO_LINK DEFINITIONS) - cmake_parse_arguments( - "BEXEC" "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} - ) - - # Resolve nested scratch prefixes without user intervention - string(REPLACE "${PROJECT_SOURCE_DIR}" "" relative_path - "${CMAKE_CURRENT_SOURCE_DIR}" - ) - if("${relative_path}" MATCHES "scratch" AND "${BEXEC_EXECNAME_PREFIX}" - STREQUAL "" - ) - get_scratch_prefix(BEXEC_EXECNAME_PREFIX) - endif() - - add_executable( - ${BEXEC_EXECNAME_PREFIX}${BEXEC_EXECNAME} "${BEXEC_SOURCE_FILES}" - ) - - target_compile_definitions( - ${BEXEC_EXECNAME_PREFIX}${BEXEC_EXECNAME} PUBLIC ${BEXEC_DEFINITIONS} - ) - - if(${PRECOMPILE_HEADERS_ENABLED} AND (NOT ${BEXEC_IGNORE_PCH})) - target_precompile_headers( - ${BEXEC_EXECNAME_PREFIX}${BEXEC_EXECNAME} REUSE_FROM stdlib_pch_exec - ) - endif() - - if(${NS3_STATIC} AND (NOT BEXEC_STANDALONE)) - target_link_libraries( - ${BEXEC_EXECNAME_PREFIX}${BEXEC_EXECNAME} ${LIB_AS_NEEDED_PRE_STATIC} - ${lib-ns3-static} - ) - elseif(${NS3_MONOLIB} AND (NOT BEXEC_STANDALONE)) - target_link_libraries( - ${BEXEC_EXECNAME_PREFIX}${BEXEC_EXECNAME} ${LIB_AS_NEEDED_PRE} - ${lib-ns3-monolib} ${LIB_AS_NEEDED_POST} - ) - else() - target_link_libraries( - ${BEXEC_EXECNAME_PREFIX}${BEXEC_EXECNAME} ${LIB_AS_NEEDED_PRE} - "${BEXEC_LIBRARIES_TO_LINK}" ${LIB_AS_NEEDED_POST} - ) - endif() - - set_runtime_outputdirectory( - "${BEXEC_EXECNAME}" "${BEXEC_EXECUTABLE_DIRECTORY_PATH}/" - "${BEXEC_EXECNAME_PREFIX}" - ) - - if(BEXEC_INSTALL_DIRECTORY_PATH) - install(TARGETS ${BEXEC_EXECNAME_PREFIX}${BEXEC_EXECNAME} - EXPORT ns3ExportTargets - RUNTIME DESTINATION ${BEXEC_INSTALL_DIRECTORY_PATH} - ) - get_property( - filename TARGET ${BEXEC_EXECNAME_PREFIX}${BEXEC_EXECNAME} - PROPERTY RUNTIME_OUTPUT_NAME - ) - add_custom_target( - uninstall_${BEXEC_EXECNAME_PREFIX}${BEXEC_EXECNAME} - COMMAND - rm ${CMAKE_INSTALL_PREFIX}/${BEXEC_INSTALL_DIRECTORY_PATH}/${filename} - ) - add_dependencies( - uninstall uninstall_${BEXEC_EXECNAME_PREFIX}${BEXEC_EXECNAME} - ) - endif() -endfunction(build_exec) - -function(scan_python_examples path) - # Skip python examples search in case the bindings are disabled - if(NOT ${ENABLE_PYTHON_BINDINGS}) - return() - endif() - - # Search for python examples - file(GLOB_RECURSE python_examples ${path}/*.py) - foreach(python_example ${python_examples}) - if(NOT (${python_example} MATCHES "examples-to-run")) - set(ns3-execs-py "${python_example};${ns3-execs-py}" - CACHE INTERNAL "list of python scripts" - ) + # Append the include directory to a list + set(include_directories ${include_directories} -I${include_dir}) endif() endforeach() + set(${output} ${include_directories} PARENT_SCOPE) endfunction() -add_custom_target(copy_all_headers) -function(copy_headers_before_building_lib libname outputdir headers visibility) - foreach(header ${headers}) - # Copy header to output directory on changes -> too darn slow - # configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${header} ${outputdir}/ - # COPYONLY) - - get_filename_component( - header_name ${CMAKE_CURRENT_SOURCE_DIR}/${header} NAME - ) - - # If output directory does not exist, create it - if(NOT (EXISTS ${outputdir})) - file(MAKE_DIRECTORY ${outputdir}) - endif() - - # If header already exists, skip symlinking/stub header creation - if(EXISTS ${outputdir}/${header_name}) - continue() - endif() - - # Create a stub header in the output directory, including the real header - # inside their respective module - get_filename_component( - ABSOLUTE_HEADER_PATH "${CMAKE_CURRENT_SOURCE_DIR}/${header}" ABSOLUTE - ) - file(WRITE ${outputdir}/${header_name} - "#include \"${ABSOLUTE_HEADER_PATH}\"\n" - ) - endforeach() -endfunction(copy_headers_before_building_lib) - -function(remove_lib_prefix prefixed_library library) - # Check if there is a lib prefix - string(FIND "${prefixed_library}" "lib" lib_pos) - - # If there is a lib prefix, try to remove it - if(${lib_pos} EQUAL 0) - # Check if we still have something remaining after removing the "lib" prefix - string(LENGTH ${prefixed_library} len) - if(${len} LESS 4) - message(FATAL_ERROR "Invalid library name: ${prefixed_library}") - endif() - - # Remove lib prefix from module name (e.g. libcore -> core) - string(SUBSTRING "${prefixed_library}" 3 -1 unprefixed_library) - else() - set(unprefixed_library ${prefixed_library}) - endif() - - # Save the unprefixed library name to the parent scope - set(${library} ${unprefixed_library} PARENT_SCOPE) -endfunction() - -function(check_for_missing_libraries output_variable_name libraries) - set(missing_dependencies) - foreach(lib ${libraries}) - # skip check for ns-3 modules if its a path to a library - if(EXISTS ${lib}) - continue() - endif() - - # check if the example depends on disabled modules - remove_lib_prefix("${lib}" lib) - - # Check if the module exists in the ns-3 modules list or if it is a - # 3rd-party library - if(NOT (${lib} IN_LIST ns3-all-enabled-modules)) - list(APPEND missing_dependencies ${lib}) - endif() - endforeach() - set(${output_variable_name} ${missing_dependencies} PARENT_SCOPE) -endfunction() +# Macros related to the definition of executables +include(ns3-executables) # Import macros used for modules and define specialized versions for src modules -include(build-support/custom-modules/ns3-module-macros.cmake) +include(ns3-module-macros) # Contrib modules counterparts of macros above -include(build-support/custom-modules/ns3-contributions.cmake) +include(ns3-contributions) + +# Macros for enabled/disabled module filtering +include(ns3-filter-modules) + +# .ns3rc configuration file parsers +include(ns3-ns3rc-parser) # Macro to build examples in ns-3-dev/examples/ macro(build_example) @@ -1885,670 +1379,41 @@ macro(build_example) if((NOT missing_dependencies) AND ${filtered_in}) # Convert boolean into text to forward argument + set(IGNORE_PCH) if(${EXAMPLE_IGNORE_PCH}) - set(IGNORE_PCH IGNORE_PCH) + set(IGNORE_PCH "IGNORE_PCH") endif() + + set(current_directory ${CMAKE_CURRENT_SOURCE_DIR}) + string(REPLACE "${PROJECT_SOURCE_DIR}" "" current_directory + "${current_directory}" + ) + if("${current_directory}" MATCHES ".*/(src|contrib)/.*") + message( + FATAL_ERROR + "build_example() macro is meant for ns-3-dev/examples, and not for modules. Use build_lib_example() instead." + ) + endif() + + get_filename_component(examplefolder ${CMAKE_CURRENT_SOURCE_DIR} NAME) + # Create example library with sources and headers # cmake-format: off build_exec( - EXECNAME ${EXAMPLE_NAME} - SOURCE_FILES ${EXAMPLE_SOURCE_FILES} - HEADER_FILES ${EXAMPLE_HEADER_FILES} - LIBRARIES_TO_LINK ${EXAMPLE_LIBRARIES_TO_LINK} ${optional_visualizer_lib} - EXECUTABLE_DIRECTORY_PATH - ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/examples/${examplefolder}/ - ${IGNORE_PCH} + EXECNAME ${EXAMPLE_NAME} + SOURCE_FILES ${EXAMPLE_SOURCE_FILES} + HEADER_FILES ${EXAMPLE_HEADER_FILES} + LIBRARIES_TO_LINK ${EXAMPLE_LIBRARIES_TO_LINK} ${ns3-optional-visualizer-lib} + EXECUTABLE_DIRECTORY_PATH + ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/examples/${examplefolder}/ + ${IGNORE_PCH} ) # cmake-format: on endif() endmacro() -function(filter_modules modules_to_filter all_modules_list filter_in) - set(new_modules_to_build) - # We are receiving variable names as arguments, so we have to "dereference" - # them first That is why we have the duplicated ${${}} - foreach(module ${${all_modules_list}}) - if(${filter_in} (${module} IN_LIST ${modules_to_filter})) - list(APPEND new_modules_to_build ${module}) - endif() - endforeach() - set(${all_modules_list} ${new_modules_to_build} PARENT_SCOPE) -endfunction() +# Macros to write the lock file +include(ns3-lock) -function(resolve_dependencies module_name dependencies contrib_dependencies) - # Create cache variables to hold dependencies list and visited - set(dependency_visited "" CACHE INTERNAL "") - set(contrib_dependency_visited "" CACHE INTERNAL "") - recursive_dependency(${module_name}) - if(${module_name} IN_LIST dependency_visited) - set(temp ${dependency_visited}) - list(REMOVE_AT temp 0) - set(${dependencies} ${temp} PARENT_SCOPE) - set(${contrib_dependencies} ${contrib_dependency_visited} PARENT_SCOPE) - else() - set(temp ${contrib_dependency_visited}) - list(REMOVE_AT temp 0) - set(${dependencies} ${dependency_visited} PARENT_SCOPE) - set(${contrib_dependencies} ${temp} PARENT_SCOPE) - endif() - unset(dependency_visited CACHE) - unset(contrib_dependency_visited CACHE) -endfunction() - -function(filter_libraries cmakelists_contents libraries) - string(REGEX MATCHALL "{lib[^}]*[^obj]}" matches "${cmakelists_content}") - list(REMOVE_ITEM matches "{libraries_to_link}") - string(REPLACE "{lib\${name" "" matches "${matches}") # special case for - # src/test - string(REPLACE "{lib" "" matches "${matches}") - string(REPLACE "}" "" matches "${matches}") - set(${libraries} ${matches} PARENT_SCOPE) -endfunction() - -function(recursive_dependency module_name) - # Read module CMakeLists.txt and search for ns-3 modules - set(src_cmakelist ${PROJECT_SOURCE_DIR}/src/${module_name}/CMakeLists.txt) - set(contrib_cmakelist - ${PROJECT_SOURCE_DIR}/contrib/${module_name}/CMakeLists.txt - ) - set(contrib FALSE) - if(EXISTS ${src_cmakelist}) - file(READ ${src_cmakelist} cmakelists_content) - elseif(EXISTS ${contrib_cmakelist}) - file(READ ${contrib_cmakelist} cmakelists_content) - set(contrib TRUE) - else() - set(cmakelists_content "") - message(${HIGHLIGHTED_STATUS} - "The CMakeLists.txt file for module ${module_name} was not found." - ) - endif() - - filter_libraries("${cmakelists_content}" matches) - - # Add this visited module dependencies to the dependencies list - if(contrib) - set(contrib_dependency_visited - "${contrib_dependency_visited};${module_name}" CACHE INTERNAL "" - ) - set(examples_cmakelists ${contrib_cmakelist}) - else() - set(dependency_visited "${dependency_visited};${module_name}" CACHE INTERNAL - "" - ) - set(examples_cmakelists ${src_cmakelist}) - endif() - - # cmake-format: off - # Scan dependencies required by this module examples - #if(${ENABLE_EXAMPLES}) - # string(REPLACE "${module_name}" "${module_name}/examples" examples_cmakelists ${examples_cmakelists}) - # if(EXISTS ${examples_cmakelists}) - # file(READ ${examples_cmakelists} cmakelists_content) - # filter_libraries(${cmakelists_content} example_matches) - # endif() - #endif() - # cmake-format: on - - # For each dependency, call this same function - set(matches "${matches};${example_matches}") - foreach(match ${matches}) - if(NOT ((${match} IN_LIST dependency_visited) - OR (${match} IN_LIST contrib_dependency_visited)) - ) - recursive_dependency(${match}) - endif() - endforeach() -endfunction() - -macro( - filter_enabled_and_disabled_modules - libs_to_build - contrib_libs_to_build - NS3_ENABLED_MODULES - NS3_DISABLED_MODULES - ns3rc_enabled_modules - ns3rc_disabled_modules -) - mark_as_advanced(ns3-all-enabled-modules) - - # Before filtering, we set a variable with all scanned modules in the src - # directory - set(scanned_modules ${${libs_to_build}}) - - # Ensure enabled and disable modules lists are using semicolons - string(REPLACE "," ";" ${NS3_ENABLED_MODULES} "${${NS3_ENABLED_MODULES}}") - string(REPLACE "," ";" ${NS3_DISABLED_MODULES} "${${NS3_DISABLED_MODULES}}") - - # Now that scanning modules finished, we can remove the disabled modules or - # replace the modules list with the ones in the enabled list - if(${NS3_ENABLED_MODULES} OR ${ns3rc_enabled_modules}) - # List of enabled modules passed by the command line overwrites list read - # from ns3rc - if(${NS3_ENABLED_MODULES}) - set(ns3rc_enabled_modules ${${NS3_ENABLED_MODULES}}) - endif() - - # Filter enabled modules - filter_modules(ns3rc_enabled_modules libs_to_build "") - filter_modules(ns3rc_enabled_modules contrib_libs_to_build "") - - # Use recursion to automatically determine dependencies required by the - # manually enabled modules - foreach(lib ${${contrib_libs_to_build}}) - resolve_dependencies(${lib} dependencies contrib_dependencies) - list(APPEND ${contrib_libs_to_build} "${contrib_dependencies}") - list(APPEND ${libs_to_build} "${dependencies}") - unset(dependencies) - unset(contrib_dependencies) - endforeach() - - foreach(lib ${${libs_to_build}}) - resolve_dependencies(${lib} dependencies contrib_dependencies) - list(APPEND ${libs_to_build} "${dependencies}") - unset(dependencies) - unset(contrib_dependencies) - endforeach() - endif() - - if(${NS3_DISABLED_MODULES} OR ${ns3rc_disabled_modules}) - # List of disabled modules passed by the command line overwrites list read - # from ns3rc - - if(${NS3_DISABLED_MODULES}) - set(ns3rc_disabled_modules ${${NS3_DISABLED_MODULES}}) - endif() - - set(all_libs ${${libs_to_build}};${${contrib_libs_to_build}}) - - # We then use the recursive dependency finding to get all dependencies of - # all modules - foreach(lib ${all_libs}) - resolve_dependencies(${lib} dependencies contrib_dependencies) - set(${lib}_dependencies "${dependencies};${contrib_dependencies}") - unset(dependencies) - unset(contrib_dependencies) - endforeach() - - # Now we can begin removing libraries that require disabled dependencies - set(disabled_libs "${${ns3rc_disabled_modules}}") - foreach(libo ${all_libs}) - foreach(lib ${all_libs}) - foreach(disabled_lib ${disabled_libs}) - if(${lib} STREQUAL ${disabled_lib}) - continue() - endif() - if(${disabled_lib} IN_LIST ${lib}_dependencies) - list(APPEND disabled_libs ${lib}) - break() # proceed to the next lib in all_libs - endif() - endforeach() - endforeach() - endforeach() - - # Clean dependencies lists - foreach(lib ${all_libs}) - unset(${lib}_dependencies) - endforeach() - - # We can filter out disabled modules - filter_modules(disabled_libs libs_to_build "NOT") - filter_modules(disabled_libs contrib_libs_to_build "NOT") - - if(core IN_LIST ${libs_to_build}) - list(APPEND ${libs_to_build} test) # include test module - endif() - endif() - - # Older CMake versions require this workaround for empty lists - if(NOT ${contrib_libs_to_build}) - set(${contrib_libs_to_build} "") - endif() - - # Filter out any eventual duplicates - list(REMOVE_DUPLICATES ${libs_to_build}) - list(REMOVE_DUPLICATES ${contrib_libs_to_build}) - - # Export list with all enabled modules (used to separate ns libraries from - # non-ns libraries in ns3_module_macros) - set(ns3-all-enabled-modules "${${libs_to_build}};${${contrib_libs_to_build}}" - CACHE INTERNAL "list with all enabled modules" - ) -endmacro() - -# Parse .ns3rc -macro(parse_ns3rc enabled_modules disabled_modules examples_enabled - tests_enabled -) - # Try to find .ns3rc - find_file(NS3RC .ns3rc PATHS /etc $ENV{HOME} $ENV{USERPROFILE} - ${PROJECT_SOURCE_DIR} NO_CACHE - ) - - # Set variables with default values (all modules, no examples nor tests) - set(${enabled_modules} "") - set(${disabled_modules} "") - set(${examples_enabled} "FALSE") - set(${tests_enabled} "FALSE") - - if(NOT (${NS3RC} STREQUAL "NS3RC-NOTFOUND")) - message(${HIGHLIGHTED_STATUS} - "Configuration file .ns3rc being used : ${NS3RC}" - ) - file(READ ${NS3RC} ns3rc_contents) - # Check if ns3rc file is CMake or Python based and act accordingly - if(ns3rc_contents MATCHES "ns3rc_*") - include(${NS3RC}) - else() - parse_python_ns3rc( - "${ns3rc_contents}" ${enabled_modules} ${examples_enabled} - ${tests_enabled} ${NS3RC} - ) - endif() - endif() -endmacro(parse_ns3rc) - -function(parse_python_ns3rc ns3rc_contents enabled_modules examples_enabled - tests_enabled ns3rc_location -) - # Save .ns3rc backup - file(WRITE ${ns3rc_location}.backup ${ns3rc_contents}) - - # Match modules_enabled list - if(ns3rc_contents MATCHES "modules_enabled.*\\[(.*).*\\]") - set(${enabled_modules} ${CMAKE_MATCH_1}) - if(${enabled_modules} MATCHES "all_modules") - # If all modules, just clean the filter and all modules will get built by - # default - set(${enabled_modules}) - else() - # If modules are listed, remove quotes and replace commas with semicolons - # transforming a string into a cmake list - string(REPLACE "," ";" ${enabled_modules} "${${enabled_modules}}") - string(REPLACE "'" "" ${enabled_modules} "${${enabled_modules}}") - string(REPLACE "\"" "" ${enabled_modules} "${${enabled_modules}}") - string(REPLACE " " "" ${enabled_modules} "${${enabled_modules}}") - string(REPLACE "\n" ";" ${enabled_modules} "${${enabled_modules}}") - list(SORT ${enabled_modules}) - - # Remove possibly empty entry - list(REMOVE_ITEM ${enabled_modules} "") - foreach(element ${${enabled_modules}}) - # Inspect each element for comments - if(${element} MATCHES "#.*") - list(REMOVE_ITEM ${enabled_modules} ${element}) - endif() - endforeach() - endif() - endif() - - string(REPLACE "True" "ON" ns3rc_contents ${ns3rc_contents}) - string(REPLACE "False" "OFF" ns3rc_contents ${ns3rc_contents}) - - # Match examples_enabled flag - if(ns3rc_contents MATCHES "examples_enabled = (ON|OFF)") - set(${examples_enabled} ${CMAKE_MATCH_1}) - endif() - - # Match tests_enabled flag - if(ns3rc_contents MATCHES "tests_enabled = (ON|OFF)") - set(${tests_enabled} ${CMAKE_MATCH_1}) - endif() - - # Save variables to parent scope - set(${enabled_modules} "${${enabled_modules}}" PARENT_SCOPE) - set(${examples_enabled} "${${examples_enabled}}" PARENT_SCOPE) - set(${tests_enabled} "${${tests_enabled}}" PARENT_SCOPE) - - # Save updated .ns3rc file - message( - ${HIGHLIGHTED_STATUS} - "The python-based .ns3rc file format is deprecated and was updated to the CMake format" - ) - configure_file( - ${PROJECT_SOURCE_DIR}/build-support/.ns3rc-template ${ns3rc_location} @ONLY - ) -endfunction(parse_python_ns3rc) - -function(log_find_searched_paths) - # Parse arguments - set(options) - set(oneValueArgs TARGET_TYPE TARGET_NAME SEARCH_RESULT SEARCH_SYSTEM_PREFIX) - set(multiValueArgs SEARCH_PATHS SEARCH_SUFFIXES) - cmake_parse_arguments( - "LOGFIND" "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} - ) - - # Get searched paths and add cmake_system_prefix_path if not explicitly marked - # not to include it - set(tsearch_paths ${LOGFIND_SEARCH_PATHS}) - if("${LOGFIND_SEARCH_SYSTEM_PREFIX}" STREQUAL "") - list(APPEND tsearch_paths "${CMAKE_SYSTEM_PREFIX_PATH}") - endif() - - set(log_find - "Looking for ${LOGFIND_TARGET_TYPE} ${LOGFIND_TARGET_NAME} in:\n" - ) - # For each search path and suffix combination, print a line - foreach(tsearch_path ${tsearch_paths}) - foreach(suffix ${LOGFIND_SEARCH_SUFFIXES}) - string(APPEND log_find - "\t${tsearch_path}${suffix}/${LOGFIND_TARGET_NAME}\n" - ) - endforeach() - endforeach() - - # Add a final line saying if the file was found and where, or if it was not - # found - if("${${LOGFIND_SEARCH_RESULT}}" STREQUAL "${LOGFIND_SEARCH_RESULT}-NOTFOUND") - string(APPEND log_find - "\n\t${LOGFIND_TARGET_TYPE} ${LOGFIND_TARGET_NAME} was not found\n" - ) - else() - string( - APPEND - log_find - "\n\t${LOGFIND_TARGET_TYPE} ${LOGFIND_TARGET_NAME} was found in ${${LOGFIND_SEARCH_RESULT}}\n" - ) - endif() - - # Replace duplicate path separators - string(REPLACE "//" "/" log_find "${log_find}") - - # Print find debug message similar to the one produced by - # CMAKE_FIND_DEBUG_MODE=true in CMake >= 3.17 - message(STATUS ${log_find}) -endfunction() - -function(find_external_library) - # Parse arguments - set(options QUIET) - set(oneValueArgs DEPENDENCY_NAME HEADER_NAME LIBRARY_NAME) - set(multiValueArgs HEADER_NAMES LIBRARY_NAMES PATH_SUFFIXES SEARCH_PATHS) - cmake_parse_arguments( - "FIND_LIB" "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} - ) - - # Set the external package/dependency name - set(name ${FIND_LIB_DEPENDENCY_NAME}) - - # We process individual and list of headers and libraries by transforming them - # into lists - set(library_names "${FIND_LIB_LIBRARY_NAME};${FIND_LIB_LIBRARY_NAMES}") - set(header_names "${FIND_LIB_HEADER_NAME};${FIND_LIB_HEADER_NAMES}") - - # Just changing the parsed argument name back to something shorter - set(search_paths ${FIND_LIB_SEARCH_PATHS}) - set(path_suffixes "${FIND_LIB_PATH_SUFFIXES}") - - set(not_found_libraries) - set(library_dirs) - set(libraries) - - # Include parent directories in the search paths to handle Bake cases - get_filename_component(parent_project_dir ${PROJECT_SOURCE_DIR} DIRECTORY) - get_filename_component( - grandparent_project_dir ${parent_project_dir} DIRECTORY - ) - set(project_parent_dirs ${parent_project_dir} ${grandparent_project_dir}) - - # Paths and suffixes where libraries will be searched on - set(library_search_paths - ${search_paths} - ${project_parent_dirs} - ${CMAKE_OUTPUT_DIRECTORY} # Search for libraries in ns-3-dev/build - ${CMAKE_INSTALL_PREFIX} # Search for libraries in the install directory - # (e.g. /usr/) - $ENV{LD_LIBRARY_PATH} # Search for libraries in LD_LIBRARY_PATH - # directories - $ENV{PATH} # Search for libraries in PATH directories - ) - # cmake-format: off - # - # Split : separated entries from environment variables - # by replacing separators with ; - # - # cmake-format: on - string(REPLACE ":" ";" library_search_paths "${library_search_paths}") - - set(suffixes /build /lib /build/lib / /bin ${path_suffixes}) - - # For each of the library names in LIBRARY_NAMES or LIBRARY_NAME - foreach(library ${library_names}) - # We mark this value is advanced not to pollute the configuration with - # ccmake with the cache variables used internally - mark_as_advanced(${name}_library_internal_${library}) - - # We search for the library named ${library} and store the results in - # ${name}_library_internal_${library} - find_library( - ${name}_library_internal_${library} ${library} - HINTS ${library_search_paths} PATH_SUFFIXES ${suffixes} - ) - # cmake-format: off - # Note: the PATH_SUFFIXES above apply to *ALL* PATHS and HINTS Which - # translates to CMake searching on standard library directories - # CMAKE_SYSTEM_PREFIX_PATH, user-settable CMAKE_PREFIX_PATH or - # CMAKE_LIBRARY_PATH and the directories listed above - # - # e.g. from Ubuntu 22.04 CMAKE_SYSTEM_PREFIX_PATH = - # /usr/local;/usr;/;/usr/local;/usr/X11R6;/usr/pkg;/opt - # - # Searched directories without suffixes - # - # ${CMAKE_SYSTEM_PREFIX_PATH}[0] = /usr/local/ - # ${CMAKE_SYSTEM_PREFIX_PATH}[1] = /usr - # ${CMAKE_SYSTEM_PREFIX_PATH}[2] = / - # ... - # ${CMAKE_SYSTEM_PREFIX_PATH}[6] = /opt - # ${LD_LIBRARY_PATH}[0] - # ... - # ${LD_LIBRARY_PATH}[m] - # ${PATH}[0] - # ... - # ${PATH}[m] - # - # Searched directories with suffixes include all of the directories above - # plus all suffixes - # PATH_SUFFIXES /build /lib /build/lib / /bin # ${path_suffixes} - # - # /usr/local/build - # /usr/local/lib - # /usr/local/build/lib - # /usr/local/bin - # ... - # - # cmake-format: on - # Or enable NS3_VERBOSE to print the searched paths - - # Print tested paths to the searched library and if it was found - if(${NS3_VERBOSE} AND (${CMAKE_VERSION} VERSION_LESS "3.17.0")) - log_find_searched_paths( - TARGET_TYPE - Library - TARGET_NAME - ${library} - SEARCH_RESULT - ${name}_library_internal_${library} - SEARCH_PATHS - ${library_search_paths} - SEARCH_SUFFIXES - ${suffixes} - ) - endif() - - # After searching the library, the internal variable should have either the - # absolute path to the library or the name of the variable appended with - # -NOTFOUND - if("${${name}_library_internal_${library}}" STREQUAL - "${name}_library_internal_${library}-NOTFOUND" - ) - # We keep track of libraries that were not found - list(APPEND not_found_libraries ${library}) - else() - # We get the name of the parent directory of the library and append the - # library to a list of found libraries - get_filename_component( - ${name}_library_dir_internal ${${name}_library_internal_${library}} - DIRECTORY - ) # e.g. lib/openflow.(so|dll|dylib|a) -> lib - list(APPEND library_dirs ${${name}_library_dir_internal}) - list(APPEND libraries ${${name}_library_internal_${library}}) - endif() - endforeach() - - # For each library that was found (e.g. /usr/lib/pthread.so), get their parent - # directory (/usr/lib) and its parent (/usr) - set(parent_dirs) - foreach(libdir ${library_dirs}) - get_filename_component(parent_libdir ${libdir} DIRECTORY) - get_filename_component(parent_parent_libdir ${parent_libdir} DIRECTORY) - list(APPEND parent_dirs ${libdir} ${parent_libdir} ${parent_parent_libdir}) - endforeach() - - set(header_search_paths - ${search_paths} - ${parent_dirs} - ${project_parent_dirs} - ${CMAKE_OUTPUT_DIRECTORY} # Search for headers in - # ns-3-dev/build - ${CMAKE_INSTALL_PREFIX} # Search for headers in the install - ) - - set(not_found_headers) - set(include_dirs) - foreach(header ${header_names}) - # The same way with libraries, we mark the internal variable as advanced not - # to pollute ccmake configuration with variables used internally - mark_as_advanced(${name}_header_internal_${header}) - set(suffixes - /build - /include - /build/include - /build/include/${name} - /include/${name} - /${name} - / - ${path_suffixes} - ) - - # cmake-format: off - # Here we search for the header file named ${header} and store the result in - # ${name}_header_internal_${header} - # - # The same way we did with libraries, here we search on - # CMAKE_SYSTEM_PREFIX_PATH, along with user-settable ${search_paths}, the - # parent directories from the libraries, CMAKE_OUTPUT_DIRECTORY and - # CMAKE_INSTALL_PREFIX - # - # And again, for each of them, for every suffix listed /usr/local/build - # /usr/local/include - # /usr/local/build/include - # /usr/local/build/include/${name} - # /usr/local/include/${name} - # ... - # - # cmake-format: on - # Or enable NS3_VERBOSE to get the searched paths printed while configuring - - find_file(${name}_header_internal_${header} ${header} - HINTS ${header_search_paths} # directory (e.g. /usr/) - ${header_skip_system_prefix} PATH_SUFFIXES ${suffixes} - ) - - # Print tested paths to the searched header and if it was found - if(${NS3_VERBOSE} AND (${CMAKE_VERSION} VERSION_LESS "3.17.0")) - log_find_searched_paths( - TARGET_TYPE - Header - TARGET_NAME - ${header} - SEARCH_RESULT - ${name}_header_internal_${header} - SEARCH_PATHS - ${header_search_paths} - SEARCH_SUFFIXES - ${suffixes} - SEARCH_SYSTEM_PREFIX - ${header_skip_system_prefix} - ) - endif() - - # If the header file was not found, append to the not-found list - if("${${name}_header_internal_${header}}" STREQUAL - "${name}_header_internal_${header}-NOTFOUND" - ) - list(APPEND not_found_headers ${header}) - else() - # If the header file was found, get their directories and the parent of - # their directories to add as include directories - get_filename_component( - header_include_dir ${${name}_header_internal_${header}} DIRECTORY - ) # e.g. include/click/ (simclick.h) -> #include should work - get_filename_component( - header_include_dir2 ${header_include_dir} DIRECTORY - ) # e.g. include/(click) -> #include should work - list(APPEND include_dirs ${header_include_dir} ${header_include_dir2}) - endif() - endforeach() - - # Remove duplicate include directories - if(include_dirs) - list(REMOVE_DUPLICATES include_dirs) - endif() - - # If we find both library and header, we export their values - if((NOT not_found_libraries) AND (NOT not_found_headers)) - set(${name}_INCLUDE_DIRS "${include_dirs}" PARENT_SCOPE) - set(${name}_LIBRARIES "${libraries}" PARENT_SCOPE) - set(${name}_HEADER ${${name}_header_internal} PARENT_SCOPE) - set(${name}_FOUND TRUE PARENT_SCOPE) - if(NOT ${FIND_LIB_QUIET}) - message(STATUS "find_external_library: ${name} was found.") - endif() - else() - set(${name}_INCLUDE_DIRS PARENT_SCOPE) - set(${name}_LIBRARIES PARENT_SCOPE) - set(${name}_HEADER PARENT_SCOPE) - set(${name}_FOUND FALSE PARENT_SCOPE) - if(NOT ${FIND_LIB_QUIET}) - message( - ${HIGHLIGHTED_STATUS} - "find_external_library: ${name} was not found. Missing headers: \"${not_found_headers}\" and missing libraries: \"${not_found_libraries}\"." - ) - endif() - endif() -endfunction() - -function(get_target_includes target output) - set(include_directories) - get_target_property(include_dirs ${target} INCLUDE_DIRECTORIES) - list(REMOVE_DUPLICATES include_dirs) - foreach(include_dir ${include_dirs}) - if(include_dir MATCHES "<") - # Skip CMake build and install interface includes - continue() - else() - # Append the include directory to a list - set(include_directories ${include_directories} -I${include_dir}) - endif() - endforeach() - set(${output} ${include_directories} PARENT_SCOPE) -endfunction() - -function(check_python_packages packages missing_packages) - set(missing) - foreach(package ${packages}) - execute_process( - COMMAND ${Python3_EXECUTABLE} -c "import ${package}" - RESULT_VARIABLE return_code OUTPUT_QUIET ERROR_QUIET - ) - if(NOT (${return_code} EQUAL 0)) - list(APPEND missing ${package}) - endif() - endforeach() - set(${missing_packages} "${missing}" PARENT_SCOPE) -endfunction() - -include(build-support/custom-modules/ns3-lock.cmake) -include(build-support/custom-modules/ns3-configtable.cmake) +# Macros to build the config table file +include(ns3-configtable) diff --git a/build-support/pip-wheel/auditwheel-exclude-list.py b/build-support/pip-wheel/auditwheel-exclude-list.py index 02ea3d24c..5b2ed6abb 100644 --- a/build-support/pip-wheel/auditwheel-exclude-list.py +++ b/build-support/pip-wheel/auditwheel-exclude-list.py @@ -8,4 +8,4 @@ for variant in ["lib", "lib64"]: continue for lib in os.listdir(lib_dir): if "libns3" in lib: - print(f"--exclude {lib}", end=' ') + print(f"--exclude {lib}", end=" ") diff --git a/build-support/pip-wheel/ns/__init__.py b/build-support/pip-wheel/ns/__init__.py index 65ea85d7a..e23d451e5 100644 --- a/build-support/pip-wheel/ns/__init__.py +++ b/build-support/pip-wheel/ns/__init__.py @@ -4,7 +4,8 @@ import sys try: import ns3.ns - sys.modules['ns'] = ns3.ns + + sys.modules["ns"] = ns3.ns except ModuleNotFoundError as e: print("Install the ns3 package with pip install ns3.", file=sys.stderr) exit(-1) diff --git a/build-support/pip-wheel/visualizer/__init__.py b/build-support/pip-wheel/visualizer/__init__.py index f1f712403..d5238feac 100644 --- a/build-support/pip-wheel/visualizer/__init__.py +++ b/build-support/pip-wheel/visualizer/__init__.py @@ -8,4 +8,4 @@ except ModuleNotFoundError as e: print("Install the ns3 package with pip install ns3.", file=sys.stderr) exit(-1) -from ns3.visualizer import start, register_plugin, set_bounds, add_initialization_hook +from ns3.visualizer import add_initialization_hook, register_plugin, set_bounds, start diff --git a/build-support/test-files/test-src-dependant-on-contrib/CMakeLists.txt b/build-support/test-files/test-src-dependent-on-contrib/CMakeLists.txt similarity index 79% rename from build-support/test-files/test-src-dependant-on-contrib/CMakeLists.txt rename to build-support/test-files/test-src-dependent-on-contrib/CMakeLists.txt index 6da487312..8597bead4 100644 --- a/build-support/test-files/test-src-dependant-on-contrib/CMakeLists.txt +++ b/build-support/test-files/test-src-dependent-on-contrib/CMakeLists.txt @@ -1,5 +1,5 @@ build_lib( - LIBNAME test-src-dependant-on-contrib + LIBNAME test-src-dependent-on-contrib SOURCE_FILES src-source.cc HEADER_FILES src-header.h LIBRARIES_TO_LINK ${libcore} diff --git a/build-support/test-files/test-src-dependant-on-contrib/examples/CMakeLists.txt b/build-support/test-files/test-src-dependent-on-contrib/examples/CMakeLists.txt similarity index 72% rename from build-support/test-files/test-src-dependant-on-contrib/examples/CMakeLists.txt rename to build-support/test-files/test-src-dependent-on-contrib/examples/CMakeLists.txt index 2146b7fac..9e6862dcd 100644 --- a/build-support/test-files/test-src-dependant-on-contrib/examples/CMakeLists.txt +++ b/build-support/test-files/test-src-dependent-on-contrib/examples/CMakeLists.txt @@ -2,5 +2,5 @@ build_lib_example( NAME source-example SOURCE_FILES source-example.cc LIBRARIES_TO_LINK - ${libtest-src-dependant-on-contrib} + ${libtest-src-dependent-on-contrib} ) diff --git a/build-support/test-files/test-src-dependant-on-contrib/examples/source-example.cc b/build-support/test-files/test-src-dependent-on-contrib/examples/source-example.cc similarity index 100% rename from build-support/test-files/test-src-dependant-on-contrib/examples/source-example.cc rename to build-support/test-files/test-src-dependent-on-contrib/examples/source-example.cc diff --git a/build-support/test-files/test-src-dependant-on-contrib/src-header.h b/build-support/test-files/test-src-dependent-on-contrib/src-header.h similarity index 100% rename from build-support/test-files/test-src-dependant-on-contrib/src-header.h rename to build-support/test-files/test-src-dependent-on-contrib/src-header.h diff --git a/build-support/test-files/test-src-dependant-on-contrib/src-source.cc b/build-support/test-files/test-src-dependent-on-contrib/src-source.cc similarity index 100% rename from build-support/test-files/test-src-dependant-on-contrib/src-source.cc rename to build-support/test-files/test-src-dependent-on-contrib/src-source.cc diff --git a/doc/contributing/pickle-to-xml.py b/doc/contributing/pickle-to-xml.py index 6a4fcebb3..9ba8ac6b3 100755 --- a/doc/contributing/pickle-to-xml.py +++ b/doc/contributing/pickle-to-xml.py @@ -7,35 +7,41 @@ # ... # -import pickle -import os import codecs +import os +import pickle + def dump_pickles(out, dirname, filename, path): - with open(os.path.join(dirname, filename), 'r', encoding='utf-8') as f: + with open(os.path.join(dirname, filename), "r", encoding="utf-8") as f: data = pickle.load(f) - with codecs.open(data['current_page_name'] + '.frag', mode='w', encoding='utf-8') as fragment_file: - fragment_file.write(data['body']) + with codecs.open( + data["current_page_name"] + ".frag", mode="w", encoding="utf-8" + ) as fragment_file: + fragment_file.write(data["body"]) out.write(' \n' % path) - out.write(' %s.frag\n' % data['current_page_name']) - if data['prev'] is not None: - out.write(' %s\n' % - (os.path.normpath(os.path.join(path, data['prev']['link'])), - data['prev']['title'])) - if data['next'] is not None: - out.write(' %s\n' % - (os.path.normpath(os.path.join(path, data['next']['link'])), - data['next']['title'])) - out.write(' \n') + out.write(" %s.frag\n" % data["current_page_name"]) + if data["prev"] is not None: + out.write( + ' %s\n' + % (os.path.normpath(os.path.join(path, data["prev"]["link"])), data["prev"]["title"]) + ) + if data["next"] is not None: + out.write( + ' %s\n' + % (os.path.normpath(os.path.join(path, data["next"]["link"])), data["next"]["title"]) + ) + out.write(" \n") - if data['next'] is not None: - next_path = os.path.normpath(os.path.join(path, data['next']['link'])) - next_filename = os.path.basename(next_path) + '.fpickle' + if data["next"] is not None: + next_path = os.path.normpath(os.path.join(path, data["next"]["link"])) + next_filename = os.path.basename(next_path) + ".fpickle" dump_pickles(out, dirname, next_filename, next_path) + import sys -sys.stdout.write('\n') -dump_pickles(sys.stdout, os.path.dirname(sys.argv[1]), os.path.basename(sys.argv[1]), '/') -sys.stdout.write('') +sys.stdout.write("\n") +dump_pickles(sys.stdout, os.path.dirname(sys.argv[1]), os.path.basename(sys.argv[1]), "/") +sys.stdout.write("") diff --git a/doc/contributing/source/coding-style.rst b/doc/contributing/source/coding-style.rst index 15941d45f..c9e01d3ad 100644 --- a/doc/contributing/source/coding-style.rst +++ b/doc/contributing/source/coding-style.rst @@ -38,6 +38,7 @@ previous versions. The following list contains the set of clang-format versions that are verified to produce consistent output among themselves. +* clang-format-17 * clang-format-16 * clang-format-15 * clang-format-14 @@ -114,8 +115,8 @@ check-style-clang-format.py To facilitate checking and fixing source code files according to the |ns3| coding style, |ns3| maintains the ``check-style-clang-format.py`` Python script (located in ``utils/``). This script is a wrapper to clang-format and provides useful options to check and fix -source code files. Additionally, it checks and fixes trailing whitespace and tabs in text -files. +source code files. Additionally, it performs other manual checks and fixes in text files +(described below). We recommend running this script over your newly introduced C++ files prior to submission as a Merge Request. @@ -160,6 +161,9 @@ For quick-reference, the most used commands are listed below: # Specific directory or file /path/to/utils/check-style-clang-format.py --fix absolute_or_relative/path/to/directory_or_file + # Modified files + git diff --name-only | xargs ./utils/check-style-clang-format.py --fix + Clang-tidy ********** @@ -1155,44 +1159,44 @@ expressions in if statements and variable declarations. For instance, the following code: - .. sourcecode:: cpp +.. sourcecode:: cpp - bool IsPositive(int n) - { - if (n > 0) - { - return true; - } - else - { - return false; - } - } + bool IsPositive(int n) + { + if (n > 0) + { + return true; + } + else + { + return false; + } + } - void ProcessNumber(int n) - { - if (IsPositive(n) == true) - { - ... - } - } + void ProcessNumber(int n) + { + if (IsPositive(n) == true) + { + ... + } + } can be rewritten as: - .. sourcecode:: cpp +.. sourcecode:: cpp - bool IsPositive(int n) - { - return n > 0; - } + bool IsPositive(int n) + { + return n > 0; + } - void ProcessNumber(int n) - { - if (IsPositive(n)) - { - ... - } - } + void ProcessNumber(int n) + { + if (IsPositive(n)) + { + ... + } + } Smart pointer boolean comparisons ================================= @@ -1349,6 +1353,32 @@ If a developer would like to propose to raise this bar to include more features than this, please email the developers list. We will move this language support forward as our minimally supported compiler moves forward. +Guidelines for using maps +========================= + +Maps (associative containers) are used heavily in ns-3 models to store +key/value pairs. The C++ standard, over time, has added various methods to +insert elements to maps, and the ns-3 codebase has made use of most or all +of these constructs. For the sake of uniformity and readability, the +following guidelines are recommended for any new code. + +Prefer the use of ``std::map`` to ``std::unordered_map`` unless there is +a measurable performance advantage. Use ``std::unordered_map`` only for +use cases in which the map does not need to be iterated or the iteration +order does not affect the results of the operation (because different +implementations of the hash function may lead to different iteration orders +on different systems). + +Keep in mind that C++ now allows several methods to insert values into +maps, and the behavior can be different when a value already exists for +a key. If the intended behavior is that the insertion should not overwrite +an existing value for the key, ``try_emplace()`` can be a good choice. If +the intention is to allow the overwriting of a key/value pair, +``insert_or_assign()`` can be a good choice. Both of the above methods +provide return values that can be checked-- in the case of ``try_emplace()``, +whether the insertion succeeded or did not occur, and in the case of +``insert_or_assign()``, whether an insertion or assignment occurred. + Miscellaneous items =================== @@ -1519,3 +1549,108 @@ explained here. // Avoid repeating the type name "MyClass" in std::less<> std::map> myMap; + + +CMake file formatting +********************* + +The ``CMakeLists.txt`` and other ``*.cmake`` files follow the formatting rules defined in +``build-support/cmake-format.yaml`` and ``build-support/cmake-format-modules.yaml``. + +The first set of rules applies to CMake files in all directories that are not modules, +while the second one applies to files within modules. + +.. _cmake-format: https://cmake-format.readthedocs.io/en/latest/cmake-format.html + +Those rules are enforced via the `cmake-format`_ tool, that can be installed via Pip. + +.. sourcecode:: console + + pip install cmake-format pyyaml + +After installing cmake-format, it can be called to fix the formatting of a CMake file +with the following command: + +.. sourcecode:: console + + cmake-format -c ./build-support/cmake-format.yaml CMakeLists.txt + +To check the formatting, add the `--check` option to the command, before specifying +the list of CMake files. + +Instead of calling this command for every single CMake file, it is recommended to use +the ``ns3`` script to run the custom targets that do that automatically. + +.. sourcecode:: console + + # Check CMake formatting + ./ns3 build cmake-format-check + + # Check and fix CMake formatting + ./ns3 build cmake-format + +Custom functions and macros need to be explicitly configured in the ``cmake-format.yaml`` files, +otherwise their formatting will be broken. + +Python file formatting +********************** + +.. _Black: https://black.readthedocs.io/en/stable/index.html +.. _Isort: https://pycqa.github.io/isort/index.html +.. _Black current style: https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html + +Python format style and rule enforcement is based on the default settings for the `Black`_ +formatter tool and `Isort`_ import sorter tool. Black default format is detailed in `Black current style`_. + +The custom settings for both tools are set in the ``pyproject.toml`` file. + +These tools that can be installed via Pip, using the following command: + +.. sourcecode:: console + + pip install black isort + +To check the formatting, add the `--check` option to the command: + +.. sourcecode:: console + + black --check . + isort --check . + +To check and fix the formatting, run the commands as follows: + +.. sourcecode:: console + + black . + isort . + +.. _MS Black formatter: https://marketplace.visualstudio.com/items?itemName=ms-python.black-formatter +.. _MS Isort: https://marketplace.visualstudio.com/items?itemName=ms-python.isort + +For VS Code users, `MS Black formatter`_ and `MS Isort`_ extensions, which repackage +Black and Isort for VS Code, can be installed to apply fixes regularly. +To configure VS Code to automatically format code when saving, editing or pasting code, +add the following configuration to ``.vscode/settings.json``: + +.. sourcecode:: json + + { + "editor.formatOnPaste": true, + "editor.formatOnSave": true, + "editor.formatOnType": true, + "[python]": { + "editor.defaultFormatter": "ms-python.black-formatter", + "editor.codeActionsOnSave": { + "source.organizeImports": "explicit", + }, + }, + "black-formatter.args": [ + "--config", + "pyproject.toml", + ], + "isort.check": true, + "isort.args": [ + "--sp", + "pyproject.toml", + ], + } diff --git a/doc/contributing/source/conf.py b/doc/contributing/source/conf.py index d468812fb..133a29fba 100644 --- a/doc/contributing/source/conf.py +++ b/doc/contributing/source/conf.py @@ -11,206 +11,203 @@ # All configuration values have a default; values that are commented out # serve to show the default. -import sys, os +import os +import sys # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('.')) +# sys.path.insert(0, os.path.abspath('.')) # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' +# needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.imgmath'] +extensions = ["sphinx.ext.imgmath"] # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # The suffix of source filenames. -source_suffix = '.rst' +source_suffix = ".rst" # The encoding of source files. -#source_encoding = 'utf-8-sig' +# source_encoding = 'utf-8-sig' # The master toctree document. -master_doc = 'index' +master_doc = "index" # General information about the project. -project = u'ns-3' -copyright = u'2015, ns-3 project' +project = "ns-3" +copyright = "2015, ns-3 project" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. -version = 'ns-3.40' +version = "ns-3.41" # The full version, including alpha/beta/rc tags. -release = 'ns-3.40' +release = "ns-3.41" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. -#language = None +# language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: -#today = '' +# today = '' # Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' +# today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = [] # The reST default role (used for this markup: `text`) to use for all documents. -#default_role = None +# default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True +# add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). -#add_module_names = True +# add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. -#show_authors = False +# show_authors = False # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +pygments_style = "sphinx" # A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] +# modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = 'ns3_html_theme' +html_theme = "ns3_html_theme" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. -#html_theme_options = {} +# html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. -html_theme_path = ['../..'] +html_theme_path = ["../.."] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". -html_title = 'Contributing' +html_title = "Contributing" # A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None +# html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. -#html_logo = None +# html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. -#html_favicon = None +# html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_static_path = ["_static"] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. -html_last_updated_fmt = '%b %d, %Y %H:%M' +html_last_updated_fmt = "%b %d, %Y %H:%M" # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. -#html_use_smartypants = True +# html_use_smartypants = True # Custom sidebar templates, maps document names to template names. -#html_sidebars = {} +# html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. -#html_additional_pages = {} +# html_additional_pages = {} # If false, no module index is generated. -#html_domain_indices = True +# html_domain_indices = True # If false, no index is generated. -#html_use_index = True +# html_use_index = True # If true, the index is split into individual pages for each letter. -#html_split_index = False +# html_split_index = False # If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True +# html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True +# html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True +# html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. -#html_use_opensearch = '' +# html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None +# html_file_suffix = None # Output file base name for HTML help builder. -htmlhelp_basename = 'ns-3doc' +htmlhelp_basename = "ns-3doc" # -- Options for LaTeX output -------------------------------------------------- # The paper size ('letter' or 'a4'). -#latex_paper_size = 'letter' +# latex_paper_size = 'letter' # The font size ('10pt', '11pt' or '12pt'). -#latex_font_size = '10pt' +# latex_font_size = '10pt' # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ - ('index', 'ns-3-contributing.tex', u'Contributing to ns-3', - u'ns-3 project', 'manual'), + ("index", "ns-3-contributing.tex", "Contributing to ns-3", "ns-3 project", "manual"), ] # The name of an image file (relative to this directory) to place at the top of # the title page. -latex_logo = '../../ns3_html_theme/static/ns-3.png' +latex_logo = "../../ns3_html_theme/static/ns-3.png" # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. -#latex_use_parts = False +# latex_use_parts = False # If true, show page references after internal links. -#latex_show_pagerefs = False +# latex_show_pagerefs = False # If true, show URL addresses after external links. -#latex_show_urls = False +# latex_show_urls = False # Additional stuff for the LaTeX preamble. -latex_preamble = '\\usepackage{amssymb}' +latex_preamble = "\\usepackage{amssymb}" # Documents to append as an appendix to all manuals. -#latex_appendices = [] +# latex_appendices = [] # If false, no module index is generated. -#latex_domain_indices = True +# latex_domain_indices = True # -- Options for manual page output -------------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [ - ('index', 'ns-3-contributing', u'Contributing to ns-3', - [u'ns-3 project'], 1) -] +man_pages = [("index", "ns-3-contributing", "Contributing to ns-3", ["ns-3 project"], 1)] diff --git a/doc/contributing/source/index.rst b/doc/contributing/source/index.rst index 798857449..c309abb24 100644 --- a/doc/contributing/source/index.rst +++ b/doc/contributing/source/index.rst @@ -8,7 +8,7 @@ follows: * Several guides that are version controlled for each release (the `latest release `_) and - `development tree `_: + `development tree `_: * Tutorial * Installation Guide diff --git a/doc/installation/source/conf.py b/doc/installation/source/conf.py index 5627815cf..9ea257835 100644 --- a/doc/installation/source/conf.py +++ b/doc/installation/source/conf.py @@ -11,206 +11,203 @@ # All configuration values have a default; values that are commented out # serve to show the default. -import sys, os +import os +import sys # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('.')) +# sys.path.insert(0, os.path.abspath('.')) # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' +# needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.imgmath'] +extensions = ["sphinx.ext.imgmath"] # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # The suffix of source filenames. -source_suffix = '.rst' +source_suffix = ".rst" # The encoding of source files. -#source_encoding = 'utf-8-sig' +# source_encoding = 'utf-8-sig' # The master toctree document. -master_doc = 'index' +master_doc = "index" # General information about the project. -project = u'ns-3' -copyright = u'2018, ns-3 project' +project = "ns-3" +copyright = "2018, ns-3 project" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. -version = 'ns-3.40' +version = "ns-3.41" # The full version, including alpha/beta/rc tags. -release = 'ns-3.40' +release = "ns-3.41" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. -#language = None +# language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: -#today = '' +# today = '' # Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' +# today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = [] # The reST default role (used for this markup: `text`) to use for all documents. -#default_role = None +# default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True +# add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). -#add_module_names = True +# add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. -#show_authors = False +# show_authors = False # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +pygments_style = "sphinx" # A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] +# modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = 'ns3_html_theme' +html_theme = "ns3_html_theme" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. -#html_theme_options = {} +# html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. -html_theme_path = ['../..'] +html_theme_path = ["../.."] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". -html_title = 'Installation guide' +html_title = "Installation guide" # A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None +# html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. -#html_logo = None +# html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. -#html_favicon = None +# html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_static_path = ["_static"] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. -html_last_updated_fmt = '%b %d, %Y %H:%M' +html_last_updated_fmt = "%b %d, %Y %H:%M" # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. -#html_use_smartypants = True +# html_use_smartypants = True # Custom sidebar templates, maps document names to template names. -#html_sidebars = {} +# html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. -#html_additional_pages = {} +# html_additional_pages = {} # If false, no module index is generated. -#html_domain_indices = True +# html_domain_indices = True # If false, no index is generated. -#html_use_index = True +# html_use_index = True # If true, the index is split into individual pages for each letter. -#html_split_index = False +# html_split_index = False # If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True +# html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True +# html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True +# html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. -#html_use_opensearch = '' +# html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None +# html_file_suffix = None # Output file base name for HTML help builder. -htmlhelp_basename = 'ns-3doc' +htmlhelp_basename = "ns-3doc" # -- Options for LaTeX output -------------------------------------------------- # The paper size ('letter' or 'a4'). -#latex_paper_size = 'letter' +# latex_paper_size = 'letter' # The font size ('10pt', '11pt' or '12pt'). -#latex_font_size = '10pt' +# latex_font_size = '10pt' # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ - ('index', 'ns-3-installation.tex', u'ns-3 Installation Guide', - u'ns-3 project', 'manual'), + ("index", "ns-3-installation.tex", "ns-3 Installation Guide", "ns-3 project", "manual"), ] # The name of an image file (relative to this directory) to place at the top of # the title page. -latex_logo = '../../ns3_html_theme/static/ns-3.png' +latex_logo = "../../ns3_html_theme/static/ns-3.png" # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. -#latex_use_parts = False +# latex_use_parts = False # If true, show page references after internal links. -#latex_show_pagerefs = False +# latex_show_pagerefs = False # If true, show URL addresses after external links. -#latex_show_urls = False +# latex_show_urls = False # Additional stuff for the LaTeX preamble. -latex_preamble = '\\usepackage{amssymb}' +latex_preamble = "\\usepackage{amssymb}" # Documents to append as an appendix to all manuals. -#latex_appendices = [] +# latex_appendices = [] # If false, no module index is generated. -#latex_domain_indices = True +# latex_domain_indices = True # -- Options for manual page output -------------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [ - ('index', 'ns-3-installation', u'ns-3 Installation', - [u'ns-3 project'], 1) -] +man_pages = [("index", "ns-3-installation", "ns-3 Installation", ["ns-3 project"], 1)] diff --git a/doc/installation/source/index.rst b/doc/installation/source/index.rst index a11a97ada..cde248368 100644 --- a/doc/installation/source/index.rst +++ b/doc/installation/source/index.rst @@ -8,7 +8,7 @@ follows: * Several guides that are version controlled for each release (the `latest release `_) and - `development tree `_: + `development tree `_: * Tutorial * Installation Guide *(this document)* @@ -20,7 +20,7 @@ follows: * `ns-3 wiki `_ This document is written in `reStructuredText `_ -for `Sphinx `_ and is maintained in the ``doc/installation`` directory of ns-3's source code. Source file column width is 100 columns. +for `Sphinx `_ and is maintained in the ``doc/installation`` directory of ns-3's source code. Source file column width is 100 columns. .. toctree:: :maxdepth: 2 diff --git a/doc/installation/source/macos.rst b/doc/installation/source/macos.rst index 2b241f85d..76d5be528 100644 --- a/doc/installation/source/macos.rst +++ b/doc/installation/source/macos.rst @@ -48,34 +48,39 @@ Homebrew and MacPorts, but macOS will not provide it due to licensing issues. | works on recent versions of both ``clang++`` and ``g++``, so for macOS, there is no need to install ``g++``. - +--------------------+---------------------------------------------------------------------+ + +--------------------+-------------------------------+-------------------------------------+ | **ns-3 Version** | **Homebrew packages** | **MacPorts packages** | - +====================+==================+==================================================+ + +====================+===============================+=====================================+ | 3.36 and later | ``cmake ninja`` | ``cmake ninja`` | - +--------------------+---------------------------------------------------------------------+ + +--------------------+-------------------------------+-------------------------------------+ | 3.35 and earlier | None | None | - +--------------------+---------------------------------------------------------------------+ + +--------------------+-------------------------------+-------------------------------------+ Recommended *********** - +-----------------------------+------------------------------------------------------------+ + +-----------------------------+------------------------+-----------------------------------+ | **Feature** | **Homebrew packages** | **MacPorts packages** | - +=============================+============================================================+ + +=============================+========================+===================================+ | Compiler cache optimization | ``ccache`` | ``ccache`` | - +-----------------------------+------------------------------------------------------------+ + +-----------------------------+------------------------+-----------------------------------+ | Code linting | ``clang-format llvm`` | clang-format included with | | | | ``clang``, need to select | | | | ``clang-XX llvm-XX`` versions | - +-----------------------------+------------------------------------------------------------+ + +-----------------------------+------------------------+-----------------------------------+ | Debugging | None | ``gdb ddd`` (ddd requires gdb) | - +-----------------------------+------------------------------------------------------------+ + +-----------------------------+------------------------+-----------------------------------+ .. note:: The ``llvm`` Homebrew package provides ``clang-tidy``, but please note that the binary is placed at ``/opt/homebrew/opt/llvm/bin/clang-tidy`` so you may need to add this path to your ``$PATH`` variable. +.. note:: + Likewise, when using MacPorts, the ``clang-tidy`` and ``clang-format`` binaries will be + placed in ``/opt/local/libexec/llvm-XX/bin`` (where ``XX` is the installed version number + such as ``16``), so you will need to add this to your ``$PATH`` variable. + .. note:: For debugging, ``lldb`` is the default debugger for llvm. Memory checkers such as Memory Graph exist for macOS, but the ns-3 team doesn't have experience with it as a diff --git a/doc/installation/source/quick-start.rst b/doc/installation/source/quick-start.rst index 5b8647df8..bb0b60454 100644 --- a/doc/installation/source/quick-start.rst +++ b/doc/installation/source/quick-start.rst @@ -80,13 +80,13 @@ Download There are two main options: -1. Download a release tarball. This will unpack to a directory such as ``ns-allinone-3.40`` +1. Download a release tarball. This will unpack to a directory such as ``ns-allinone-3.41`` containing |ns3| and some other programs. Below is a command-line download using ``wget``, but a browser download will also work:: - $ wget https://www.nsnam.org/releases/ns-allinone-3.40.tar.bz2 - $ tar xfj ns-allinone-3.40.tar.bz2 - $ cd ns-allinone-3.40/ns-3.40 + $ wget https://www.nsnam.org/releases/ns-allinone-3.41.tar.bz2 + $ tar xfj ns-allinone-3.41.tar.bz2 + $ cd ns-allinone-3.41/ns-3.41 2. Clone |ns3| from the Git repository. The ``ns-3-allinone`` can be cloned, as well as ``ns-3-dev`` by itself. Below, we illustrate the latter:: @@ -99,7 +99,7 @@ you clone |ns3|, your directory will be named ``ns-3-dev``. By default, Git wil the |ns3| ``master`` branch, which is a development branch. All |ns3| releases are tagged in Git, so if you would then like to check out a past release, you can do so as follows:: - $ git checkout -b ns-3.40-release ns-3.40 + $ git checkout -b ns-3.41-release ns-3.41 In this quick-start, we are omitting download and build instructions for optional |ns3| modules, the ``NetAnim`` animator, Python bindings, and ``NetSimulyzer``. The diff --git a/doc/manual/Makefile b/doc/manual/Makefile index 893ba5ba8..a14737fca 100644 --- a/doc/manual/Makefile +++ b/doc/manual/Makefile @@ -77,6 +77,7 @@ SOURCEFIGS = \ figures/hotspot-setup.png \ figures/hotspot-top-down.png \ figures/perfetto-trace-cmake.png \ + figures/time-consuming-event-handling.png \ figures/uprof-collect-callstack.png \ figures/uprof-profile-application.png \ figures/uprof-select-events.png \ diff --git a/doc/manual/figures/time-consuming-event-handling.png b/doc/manual/figures/time-consuming-event-handling.png new file mode 100644 index 000000000..c3c7672d6 Binary files /dev/null and b/doc/manual/figures/time-consuming-event-handling.png differ diff --git a/doc/manual/source/callbacks.rst b/doc/manual/source/callbacks.rst index 33a68f590..94cd33d70 100644 --- a/doc/manual/source/callbacks.rst +++ b/doc/manual/source/callbacks.rst @@ -511,8 +511,8 @@ with one or more bound arguments:: template class SpecificFunctor : public Functor - { - public: + { + public: SpecificFunctor(T* p, int (T::*_pmi)(ARG arg), BOUND_ARG boundArg) { m_p = p; @@ -524,11 +524,11 @@ with one or more bound arguments:: { (*m_p.*m_pmi)(m_boundArg, arg); } - private: + private: void (T::*m_pmi)(ARG arg); T* m_p; BOUND_ARG m_boundArg; - }; + }; You can see that when the specific functor is created, the bound argument is saved in the functor / callback object itself. When the ``operator()`` is invoked with diff --git a/doc/manual/source/conf.py b/doc/manual/source/conf.py index c3cfee573..6396e1940 100644 --- a/doc/manual/source/conf.py +++ b/doc/manual/source/conf.py @@ -20,21 +20,22 @@ # import sys # sys.path.insert(0, os.path.abspath('.')) -import sys, os +import os +import sys # To change default code-block format in Latex to footnotesize (8pt) # Tip from https://stackoverflow.com/questions/9899283/how-do-you-change-the-code-example-font-size-in-latex-pdf-output-with-sphinx/9955928 # Note: sizes are \footnotesize (8pt), \small (9pt), and \normalsize (10pt). -#from sphinx.highlighting import PygmentsBridge -#from pygments.formatters.latex import LatexFormatter +# from sphinx.highlighting import PygmentsBridge +# from pygments.formatters.latex import LatexFormatter # -#class CustomLatexFormatter(LatexFormatter): +# class CustomLatexFormatter(LatexFormatter): # def __init__(self, **options): # super(CustomLatexFormatter, self).__init__(**options) # self.verboptions = r"formatcom=\footnotesize" # -#PygmentsBridge.latex_formatter = CustomLatexFormatter +# PygmentsBridge.latex_formatter = CustomLatexFormatter # -- General configuration ------------------------------------------------ @@ -45,37 +46,37 @@ import sys, os # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. -extensions = ['sphinx.ext.imgmath'] +extensions = ["sphinx.ext.imgmath"] # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # # source_suffix = ['.rst', '.md'] -source_suffix = '.rst' +source_suffix = ".rst" # The encoding of source files. # # source_encoding = 'utf-8-sig' # The master toctree document. -master_doc = 'index' +master_doc = "index" # General information about the project. -project = u'ns-3 project' -copyright = u'2006-2019' -#author = u'test' +project = "ns-3 project" +copyright = "2006-2019, ns-3 project" +# author = u'test' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. -version = u'ns-3.40' +version = "ns-3.41" # The full version, including alpha/beta/rc tags. -release = u'ns-3.40' +release = "ns-3.41" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -96,7 +97,7 @@ language = None # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # These patterns also affect html_static_path and html_extra_path -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] # The reST default role (used for this markup: `text`) to use for all # documents. @@ -118,7 +119,7 @@ exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] # show_authors = False # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +pygments_style = "sphinx" # A list of ignored prefixes for module index sorting. # modindex_common_prefix = [] @@ -135,7 +136,7 @@ todo_include_todos = False # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -html_theme = 'ns3_html_theme' +html_theme = "ns3_html_theme" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the @@ -144,13 +145,13 @@ html_theme = 'ns3_html_theme' # html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. -html_theme_path = ['../..'] +html_theme_path = ["../.."] # The name for this set of Sphinx documents. # " v documentation" by default. # # html_title = 'est vtest' -html_title = 'Manual' +html_title = "Manual" # A shorter title for the navigation bar. Default is the same as html_title. # @@ -170,7 +171,7 @@ html_title = 'Manual' # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_static_path = ["_static"] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied @@ -182,7 +183,7 @@ html_static_path = ['_static'] # bottom, using the given strftime format. # The empty string is equivalent to '%b %d, %Y'. # -html_last_updated_fmt = '%b %d, %Y %H:%M' +html_last_updated_fmt = "%b %d, %Y %H:%M" # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. @@ -250,7 +251,7 @@ html_last_updated_fmt = '%b %d, %Y %H:%M' # html_search_scorer = 'scorer.js' # Output file base name for HTML help builder. -htmlhelp_basename = 'ns-3doc' +htmlhelp_basename = "ns-3doc" # -- Options for LaTeX output --------------------------------------------- @@ -258,11 +259,9 @@ latex_elements = { # The paper size ('letterpaper' or 'a4paper'). # # 'papersize': 'letterpaper', - # The font size ('10pt', '11pt' or '12pt'). # # 'pointsize': '10pt', - # Additional stuff for the LaTeX preamble. # # VerbatimBorderColor: make the box around code samples blend into the background @@ -275,10 +274,10 @@ latex_elements = { # See above to change the font size of verbatim code blocks # # 'preamble': '', - 'preamble': u'''\\usepackage{amssymb} + "preamble": """\\usepackage{amssymb} \\definecolor{VerbatimBorderColor}{rgb}{1,1,1} \\renewcommand{\\sphinxcode}[1]{\\texttt{\\small{#1}}} -''' +""" # Latex figure (float) alignment # # 'figure_align': 'htbp', @@ -288,14 +287,13 @@ latex_elements = { # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - ('index', 'ns-3-manual.tex', u'ns-3 Manual', - u'ns-3 project', 'manual'), + ("index", "ns-3-manual.tex", "ns-3 Manual", "ns-3 project", "manual"), ] # The name of an image file (relative to this directory) to place at the top of # the title page. # -latex_logo = '../../ns3_html_theme/static/ns-3.png' +latex_logo = "../../ns3_html_theme/static/ns-3.png" # If true, show page references after internal links. # @@ -324,10 +322,7 @@ latex_logo = '../../ns3_html_theme/static/ns-3.png' # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [ - ('index', 'ns-3-manual', u'ns-3 Manual', - [u'ns-3 project'], 1) -] +man_pages = [("index", "ns-3-manual", "ns-3 Manual", ["ns-3 project"], 1)] # If true, show URL addresses after external links. # @@ -335,11 +330,11 @@ man_pages = [ # -- Options for texinfo output --------------------------------------- -#texinfo_documents = [ +# texinfo_documents = [ # (master_doc, 'test', u'test Documentation', # author, 'test', 'One line description of project.', # 'Miscellaneous'), -#] +# ] # Documents to append as an appendix to all manuals. # diff --git a/doc/manual/source/events.rst b/doc/manual/source/events.rst index 26a95711e..9d14da677 100644 --- a/doc/manual/source/events.rst +++ b/doc/manual/source/events.rst @@ -36,7 +36,79 @@ This chapter of the manual describes these fundamental objects Event ***** -*To be completed* +An event represents something that changes the simulation status, i.e., +between two events the simulation status does not change, and the event +will likely change it (it could also not change anything). + +Note that another way to understand an event is to consider it as a delayed +function call. With the due differences, a discrete event simulation is not +much different from a "normal" program where the functions are not called +immediately, but are marked with a "time", and the time is used to decide +the order of the functions execution. + +The time, of course, is a simulated time, and is quite different from the +"real" time. Depending on the simulation complexity the simulated time +can advance faster or slower then the "real" time, but like a "real" time +can only go forward. + +An example of an event is the reception of a packet, or the expiration +of a timer. + +An event is represented by: + +* The time at which the event will happen +* A pointer to the function that will "handle" the event, +* The parameters of the function that will handle the event (if any), +* Other internal structures. + +An event is scheduled through a call to ``Simulator::Schedule``, and once +scheduled, it can be canceled or removed. +Removal implies removal from the scheduler data structure, while cancel +keeps them in the data structure but sets a boolean flag that suppresses +calling the bound event function at the scheduled time. When an event is +scheduled by the Simulator, an ``EventId`` is returned. The client may use +this event ID to later cancel or remove the event; see the example program +``src/core/examples/sample-simulator.{cc,py}`` for example usage. +Cancelling an event is typically less computationally expensive than +removing it, but cancelled events consumes more memory in the scheduler +data structure, which might impact its performances. + +Events are stored by the simulator in a scheduler data +structure. Events are handled in increasing order of +simulator time, and in the case of two events with the same +scheduled time, the event with the lowest unique ID (a +monotonically increasing counter) will be handled first. +In other words tied events are handled in FIFO order. + +Note that concurrent events (events that happen at the very same time) +are unlikely in a real system - not to say impossible. In |ns-3| +concurrent events are common for a number of reasons, one of them +being the time representation. While developing a model this must +be carefully taken into account. + +During the event execution, the simulation time will not advance, i.e., each +event is executed in zero time. This is a common assumption in +discrete event simulations, and holds when the computational complexity of +the operations executed in the event is negligible. +When this assumption does not hold, it is necessary to schedule a second event +to mimic the end of the computationally intensive task. + +As an example, suppose to have a device that receives a packet and has to +perform a complex analysis on it (e.g., an image processing task). The +sequence of events will be: + +* T(t) - Packet reception and processing, save the result somewhere, and + schedule an event in (t+d) marking the end of the data processing. +* T(t+d) - Retrieve the data, and do other stuff based them. + +So, even if the data processing actually did return a result in the +execution of the first event, the data is considered valid only after +the second event. + +The image below can be useful to clarify the idea. + +.. image:: figures/time-consuming-event-handling.png + Simulator ********* @@ -219,7 +291,7 @@ or by using a command line argument .. sourcecode:: terminal - $ ./ns3 run "... -–SimulatorImplementationType=ns3::DistributedSimulatorImpl" + $ ./ns3 run "... --SimulatorImplementationType=ns3::DistributedSimulatorImpl" In addition to the basic simulator engines there is a general facility used to build "adapters" which provide small behavior modifications to one of diff --git a/doc/manual/source/index.rst b/doc/manual/source/index.rst index f2bf761da..1d6835f14 100644 --- a/doc/manual/source/index.rst +++ b/doc/manual/source/index.rst @@ -8,7 +8,7 @@ follows: * Several guides that are version controlled for each release (the `latest release `_) and - `development tree `_: + `development tree `_: * Tutorial * Installation Guide diff --git a/doc/manual/source/new-models.rst b/doc/manual/source/new-models.rst index db813d2c1..7c0cb6d01 100644 --- a/doc/manual/source/new-models.rst +++ b/doc/manual/source/new-models.rst @@ -324,9 +324,8 @@ Second, each class must implement a static public member function called Third, it is a good idea to implement constructors and destructors rather than to let the compiler generate them, and to make the destructor virtual. In C++, note also that copy assignment operator and copy constructors are auto-generated -if they are not defined, so if you do not want those, you should implement those -as private members. This aspect of C++ is discussed in Scott Meyers' Effective -C++ book. item 45. +if they are not defined, so if you do not want those, you should declare them +as ``= delete``. Let's now look at some corresponding skeletal implementation code in the .cc file.:: @@ -385,6 +384,29 @@ every class that defines a new GetTypeId method, and it does the actual registration of the class into the system. The :ref:`Object-model` chapter discusses this in more detail. +Note: Template classes should both export the instantiated template and call +``NS_OBJECT_TEMPLATE_CLASS_DEFINE (TemplateClass, TemplateArgument);`` +to prevent the same template from being instantiated more than a single +time in different modules. This prevents errors such as +``Trying to allocate twice the same uid: TemplateClass``. + +An example for the ``CounterCalculator``:: + + //.h file + namespace ns3 + { + extern template class CounterCalculator; + } + //.cc file + #include + namespace ns3 + { + NS_OBJECT_TEMPLATE_CLASS_DEFINE (CounterCalculator, uint32_t); + } + +More details can be found in `issue #761 `_. + + Including External Files ++++++++++++++++++++++++ diff --git a/doc/manual/source/new-modules.rst b/doc/manual/source/new-modules.rst index f5a24db67..a700bc7c9 100644 --- a/doc/manual/source/new-modules.rst +++ b/doc/manual/source/new-modules.rst @@ -419,7 +419,7 @@ depend on ``ns3`` configuration variables. For example, .. sourcecode:: python - ("realtime-udp-echo.py", "ENABLE_REAL_TIME == False"), + ("brite-generic-example", "ENABLE_BRITE == True", "False"), Step 8 - Configure and Build diff --git a/doc/manual/source/profiling.rst b/doc/manual/source/profiling.rst index 69cd7e848..e338cb53c 100644 --- a/doc/manual/source/profiling.rst +++ b/doc/manual/source/profiling.rst @@ -467,7 +467,7 @@ Performance Profilers .. _Perf : https://perf.wiki.kernel.org/index.php/Tutorial .. _Hotspot : https://github.com/KDAB/hotspot .. _AMD uProf : https://www.amd.com/en/developer/uprof.html -.. _Intel VTune : https://www.intel.com/content/www/us/en/develop/documentation/get-started-with-vtune/top.html +.. _Intel VTune : https://www.intel.com/content/www/us/en/docs/vtune-profiler/get-started-guide/2023-1/overview.html .. _Windows Performance Toolkit : https://docs.microsoft.com/en-us/windows-hardware/test/wpt/ .. _Sysprof : https://wiki.gnome.org/Apps/Sysprof .. _Oprofile : https://oprofile.sourceforge.io/faq/ diff --git a/doc/manual/source/python.rst b/doc/manual/source/python.rst index 38dbf57ae..5b1a13173 100644 --- a/doc/manual/source/python.rst +++ b/doc/manual/source/python.rst @@ -632,7 +632,7 @@ in the ``ns-3-dev/setup.py`` file. .. sourcecode:: yaml # Configure and build wheel - - $PYTHON setup.py bdist_wheel build_ext "-DNS3_USE_LIB64=TRUE" + - $PYTHON setup.py bdist_wheel build_ext At this point, we have a wheel that only works in the current system, since external libraries are not shipped. diff --git a/doc/manual/source/random-variables.rst b/doc/manual/source/random-variables.rst index a42f9666a..ed6e9afc3 100644 --- a/doc/manual/source/random-variables.rst +++ b/doc/manual/source/random-variables.rst @@ -261,6 +261,8 @@ can also create their own custom random variables by deriving from class * class :cpp:class:`ZetaRandomVariable` * class :cpp:class:`DeterministicRandomVariable` * class :cpp:class:`EmpiricalRandomVariable` +* class :cpp:class:`BinomialRandomVariable` +* class :cpp:class:`BernoulliRandomVariable` Semantics of RandomVariableStream objects ***************************************** diff --git a/doc/manual/source/troubleshoot.rst b/doc/manual/source/troubleshoot.rst index d3b88c836..21a2bc98c 100644 --- a/doc/manual/source/troubleshoot.rst +++ b/doc/manual/source/troubleshoot.rst @@ -30,8 +30,8 @@ Here is an example of what might occur:: The error message says that the program terminated unsuccessfuly, but it is not clear from this information what might be wrong. To examine more -closely, try running it under the `gdb debugger -`_: +closely, try running it under the +`gdb debugger `_: .. sourcecode:: bash diff --git a/doc/manual/source/utilities.rst b/doc/manual/source/utilities.rst index 491e58da1..bc2705131 100644 --- a/doc/manual/source/utilities.rst +++ b/doc/manual/source/utilities.rst @@ -94,10 +94,10 @@ Command-line Arguments Program Options: --all: use all schedulers [false] - --cal: use CalendarSheduler [false] + --cal: use CalendarScheduler [false] --calrev: reverse ordering in the CalendarScheduler [false] --heap: use HeapScheduler [false] - --list: use ListSheduler [false] + --list: use ListScheduler [false] --map: use MapScheduler (default) [true] --pri: use PriorityQueue [false] --debug: enable debugging output [false] diff --git a/doc/manual/source/working-with-cmake.rst b/doc/manual/source/working-with-cmake.rst index 562ecd063..9527c0ca4 100644 --- a/doc/manual/source/working-with-cmake.rst +++ b/doc/manual/source/working-with-cmake.rst @@ -73,13 +73,13 @@ print the configuration options: ~$ cd ns-3-dev ~/ns-3-dev$ ./ns3 configure --help usage: ns3 configure [-h] [-d {debug,release,optimized}] [-G G] - [--cxx-standard CXX_STANDARD] [--enable-asserts] - [--disable-asserts] [--enable-examples] - [--disable-examples] [--enable-logs] - [--disable-logs] [--enable-tests] - [--disable-tests] [--enable-verbose] - [--disable-verbose] - ... + [--cxx-standard CXX_STANDARD] [--enable-asserts] + [--disable-asserts] [--enable-examples] + [--disable-examples] [--enable-logs] + [--disable-logs] [--enable-tests] + [--disable-tests] [--enable-verbose] + [--disable-verbose] + ... positional arguments: configure @@ -2269,7 +2269,7 @@ listed by ``./ns3 show targets`` or your IDE, check if all its dependencies were EXECNAME ${EXAMPLE_NAME} SOURCE_FILES ${EXAMPLE_SOURCE_FILES} HEADER_FILES ${EXAMPLE_HEADER_FILES} - LIBRARIES_TO_LINK ${EXAMPLE_LIBRARIES_TO_LINK} ${optional_visualizer_lib} + LIBRARIES_TO_LINK ${EXAMPLE_LIBRARIES_TO_LINK} ${ns3-optional-visualizer-lib} EXECUTABLE_DIRECTORY_PATH ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/examples/${examplefolder}/ ${IGNORE_PCH} @@ -2741,8 +2741,8 @@ Then we check if the |ns3| modules required by the example are enabled to be bui If the list ``missing_dependencies`` is empty, we create the example. Otherwise, we skip it. The example can be linked to the current module (``${lib${BLIB_EXAMPLE_LIBNAME}}``) and other libraries to link (``${BLIB_EXAMPLE_LIBRARIES_TO_LINK}``) and optionally to the visualizer -module (``${optional_visualizer_lib}``). -If the visualizer module is not enabled, ``optional_visualizer_lib`` is empty. +module (``${ns3-optional-visualizer-lib}``). +If the visualizer module is not enabled, ``ns3-optional-visualizer-lib`` is empty. The example can also be linked to a single |ns3| shared library (``lib-ns3-monolib``) or a single |ns3| static library (``lib-ns3-static``), if either ``NS3_MONOLIB=ON`` or ``NS3_STATIC=ON``. @@ -2776,7 +2776,7 @@ Note that both of these options are handled by the ``build_exec`` macro. HEADER_FILES ${BLIB_EXAMPLE_HEADER_FILES} LIBRARIES_TO_LINK ${lib${BLIB_EXAMPLE_LIBNAME}} ${BLIB_EXAMPLE_LIBRARIES_TO_LINK} - ${optional_visualizer_lib} + ${ns3-optional-visualizer-lib} EXECUTABLE_DIRECTORY_PATH ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${FOLDER}/ ${IGNORE_PCH} ) @@ -2950,7 +2950,7 @@ manage dependencies. Here is an example for Doxygen: # This custom macro checks for dependencies CMake find_package and program # dependencies and return the missing dependencies in the third argument - check_deps("" "doxygen;dot;dia" doxygen_docs_missing_deps) + check_deps(doxygen_docs_missing_deps EXECUTABLES doxygen dot dia python3) # If the variable contains missing dependencies, we stop processing doxygen targets if(doxygen_docs_missing_deps) diff --git a/doc/manual/source/working-with-git.rst b/doc/manual/source/working-with-git.rst index 161966094..dc6a5d1d5 100644 --- a/doc/manual/source/working-with-git.rst +++ b/doc/manual/source/working-with-git.rst @@ -368,7 +368,7 @@ We change the VERSION field from '3-dev' to '3.34':: $ cat VERSION 3.34 -We next change the file conf.py in the contributing, tutorial, manual, and models directories +We next change the file conf.py in the contributing, installation, tutorial, manual, and models directories to change the strings 'ns-3-dev' to ns-3.34. When you are done, the 'git diff --stat' command should show: @@ -377,10 +377,11 @@ When you are done, the 'git diff --stat' command should show: VERSION | 2 +- doc/contributing/source/conf.py | 4 ++-- + doc/installation/source/conf.py | 4 ++-- doc/manual/source/conf.py | 4 ++-- doc/models/source/conf.py | 4 ++-- doc/tutorial/source/conf.py | 4 ++-- - 5 files changed, 9 insertions(+), 9 deletions(-) + 6 files changed, 11 insertions(+), 11 deletions(-) Make a commit of these files: @@ -404,6 +405,8 @@ Next, make the following change to RELEASE_NOTES.md and commit it: Commit this change: +:: + $ git commit -m"Update availability in RELEASE_NOTES.md" RELEASE_NOTES.md Finally, add a Git annotated tag: diff --git a/doc/manual/source/working-with-gitlab-ci-local.rst b/doc/manual/source/working-with-gitlab-ci-local.rst index 6dec6a81b..7a4b30b2a 100644 --- a/doc/manual/source/working-with-gitlab-ci-local.rst +++ b/doc/manual/source/working-with-gitlab-ci-local.rst @@ -167,3 +167,15 @@ Artifacts built by the CI jobs will be stored in separate subfolders based on the job name. ``~/ns-3-dev/.gitlab-ci-local/artifacts/jobname`` + +Note: some jobs may access the ``CI_DEFAULT_BRANCH`` environment variable, +which is set by default to ``main`` instead of ``master``. To change that, we need +to create a file ``~/.gitlab-ci-local/variables.yml`` containing the following: + +.. sourcecode:: YAML + + global: + CI_DEFAULT_BRANCH: "master" + +In case you are using Docker with root, you need to create this file in +``/root/.gitlab-ci-local/variables.yml``. diff --git a/doc/models/Makefile b/doc/models/Makefile index 2f9405c7e..d36619895 100644 --- a/doc/models/Makefile +++ b/doc/models/Makefile @@ -145,6 +145,8 @@ SOURCEFIGS = \ $(SRC)/wifi/doc/source/figures/ack-su-format.pdf \ $(SRC)/wifi/doc/source/figures/ack-su-format.png \ $(SRC)/wifi/doc/source/figures/assoc-manager.eps \ + $(SRC)/wifi/doc/source/figures/emlsr-dl-txop.eps \ + $(SRC)/wifi/doc/source/figures/emlsr-ul-txop.eps \ $(SRC)/wifi/doc/source/figures/mu-bar.pdf \ $(SRC)/wifi/doc/source/figures/mu-bar.png \ $(SRC)/wifi/doc/source/figures/aggr-mu-bar.pdf \ @@ -466,6 +468,8 @@ IMAGES_EPS = \ $(FIGURES)/energyFramework.eps \ $(FIGURES)/clear-channel.eps \ $(FIGURES)/assoc-manager.eps \ + $(FIGURES)/emlsr-dl-txop.eps \ + $(FIGURES)/emlsr-ul-txop.eps \ $(FIGURES)/nist-frame-success-rate.eps \ $(FIGURES)/nist-frame-success-rate-n.eps \ $(FIGURES)/nist-frame-success-rate-ac.eps \ @@ -545,6 +549,8 @@ $(FIGURES)/nist-frame-success-rate-n.pdf_width = 12cm $(FIGURES)/nist-frame-success-rate-ac.pdf_width = 12cm $(FIGURES)/nist-frame-success-rate-ax.pdf_width = 12cm $(FIGURES)/assoc-manager.pdf_width = 12cm +$(FIGURES)/emlsr-dl-txop.pdf_width = 12cm +$(FIGURES)/emlsr-ul-txop.pdf_width = 12cm IMAGES_PNG = ${IMAGES_EPS:.eps=.png} IMAGES_PDF = ${IMAGES_EPS:.eps=.pdf} diff --git a/doc/models/source/conf.py b/doc/models/source/conf.py index 642cc2eeb..665266b9b 100644 --- a/doc/models/source/conf.py +++ b/doc/models/source/conf.py @@ -20,21 +20,22 @@ # import sys # sys.path.insert(0, os.path.abspath('.')) -import sys, os +import os +import sys # To change default code-block format in Latex to footnotesize (8pt) # Tip from https://stackoverflow.com/questions/9899283/how-do-you-change-the-code-example-font-size-in-latex-pdf-output-with-sphinx/9955928 # Note: sizes are \footnotesize (8pt), \small (9pt), and \normalsize (10pt). -#from sphinx.highlighting import PygmentsBridge -#from pygments.formatters.latex import LatexFormatter +# from sphinx.highlighting import PygmentsBridge +# from pygments.formatters.latex import LatexFormatter # -#class CustomLatexFormatter(LatexFormatter): +# class CustomLatexFormatter(LatexFormatter): # def __init__(self, **options): # super(CustomLatexFormatter, self).__init__(**options) # self.verboptions = r"formatcom=\footnotesize" # -#PygmentsBridge.latex_formatter = CustomLatexFormatter +# PygmentsBridge.latex_formatter = CustomLatexFormatter # -- General configuration ------------------------------------------------ @@ -45,37 +46,37 @@ import sys, os # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. -extensions = ['sphinx.ext.imgmath'] +extensions = ["sphinx.ext.imgmath"] # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # # source_suffix = ['.rst', '.md'] -source_suffix = '.rst' +source_suffix = ".rst" # The encoding of source files. # # source_encoding = 'utf-8-sig' # The master toctree document. -master_doc = 'index' +master_doc = "index" # General information about the project. -project = u'ns-3 project' -copyright = u'2006-2019' -#author = u'test' +project = "ns-3 project" +copyright = "2006-2019, ns-3 project" +# author = u'test' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. -version = u'ns-3.40' +version = "ns-3.41" # The full version, including alpha/beta/rc tags. -release = u'ns-3.40' +release = "ns-3.41" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -96,7 +97,7 @@ language = None # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # These patterns also affect html_static_path and html_extra_path -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] # The reST default role (used for this markup: `text`) to use for all # documents. @@ -118,7 +119,7 @@ exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] # show_authors = False # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +pygments_style = "sphinx" # A list of ignored prefixes for module index sorting. # modindex_common_prefix = [] @@ -135,7 +136,7 @@ todo_include_todos = False # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -html_theme = 'ns3_html_theme' +html_theme = "ns3_html_theme" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the @@ -144,18 +145,18 @@ html_theme = 'ns3_html_theme' # html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. -html_theme_path = ['../..'] +html_theme_path = ["../.."] # The name for this set of Sphinx documents. # " v documentation" by default. # # html_title = 'est vtest' -html_title = 'Model Library' +html_title = "Model Library" # A shorter title for the navigation bar. Default is the same as html_title. # # html_short_title = None -html_short_title = 'Models' +html_short_title = "Models" # The name of an image file (relative to this directory) to place at the top # of the sidebar. @@ -171,7 +172,7 @@ html_short_title = 'Models' # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_static_path = ["_static"] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied @@ -183,7 +184,7 @@ html_static_path = ['_static'] # bottom, using the given strftime format. # The empty string is equivalent to '%b %d, %Y'. # -html_last_updated_fmt = '%b %d, %Y %H:%M' +html_last_updated_fmt = "%b %d, %Y %H:%M" # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. @@ -251,7 +252,7 @@ html_last_updated_fmt = '%b %d, %Y %H:%M' # html_search_scorer = 'scorer.js' # Output file base name for HTML help builder. -htmlhelp_basename = 'ns-3doc' +htmlhelp_basename = "ns-3doc" # -- Options for LaTeX output --------------------------------------------- @@ -259,11 +260,9 @@ latex_elements = { # The paper size ('letterpaper' or 'a4paper'). # # 'papersize': 'letterpaper', - # The font size ('10pt', '11pt' or '12pt'). # # 'pointsize': '10pt', - # Additional stuff for the LaTeX preamble. # # VerbatimBorderColor: make the box around code samples blend into the background @@ -276,10 +275,10 @@ latex_elements = { # See above to change the font size of verbatim code blocks # # 'preamble': '', - 'preamble': u'''\\usepackage{amssymb} + "preamble": """\\usepackage{amssymb} \\definecolor{VerbatimBorderColor}{rgb}{1,1,1} \\renewcommand{\\sphinxcode}[1]{\\texttt{\\small{#1}}} -''' +""" # Latex figure (float) alignment # # 'figure_align': 'htbp', @@ -289,14 +288,13 @@ latex_elements = { # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - ('index', 'ns-3-model-library.tex', u'ns-3 Model Library', - u'ns-3 project', 'manual'), + ("index", "ns-3-model-library.tex", "ns-3 Model Library", "ns-3 project", "manual"), ] # The name of an image file (relative to this directory) to place at the top of # the title page. # -latex_logo = '../../ns3_html_theme/static/ns-3.png' +latex_logo = "../../ns3_html_theme/static/ns-3.png" # If true, show page references after internal links. # @@ -325,10 +323,7 @@ latex_logo = '../../ns3_html_theme/static/ns-3.png' # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [ - ('index', 'ns-3-model-library', u'ns-3 Model Library', - [u'ns-3 project'], 1) -] +man_pages = [("index", "ns-3-model-library", "ns-3 Model Library", ["ns-3 project"], 1)] # If true, show URL addresses after external links. # @@ -336,11 +331,11 @@ man_pages = [ # -- Options for texinfo output --------------------------------------- -#texinfo_documents = [ +# texinfo_documents = [ # (master_doc, 'test', u'test Documentation', # author, 'test', 'One line description of project.', # 'Miscellaneous'), -#] +# ] # Documents to append as an appendix to all manuals. # diff --git a/doc/models/source/index.rst b/doc/models/source/index.rst index 205b92d40..50cb6bb58 100644 --- a/doc/models/source/index.rst +++ b/doc/models/source/index.rst @@ -8,7 +8,7 @@ follows: * Several guides that are version controlled for each release (the `latest release `_) and - `development tree `_: + `development tree `_: * Tutorial * Installation Guide diff --git a/doc/ns3_html_theme/ns3_doxy_footer.html b/doc/ns3_html_theme/ns3_doxy_footer.html index fa87b7c5e..1e57ea8c2 100644 --- a/doc/ns3_html_theme/ns3_doxy_footer.html +++ b/doc/ns3_html_theme/ns3_doxy_footer.html @@ -9,14 +9,14 @@ $navpath + doxygen $doxygenversion diff --git a/doc/ns3_html_theme/static/ns3_stylesheet.css b/doc/ns3_html_theme/static/ns3_stylesheet.css index e29ba9ce8..dd32d1aab 100644 --- a/doc/ns3_html_theme/static/ns3_stylesheet.css +++ b/doc/ns3_html_theme/static/ns3_stylesheet.css @@ -353,4 +353,16 @@ div.sphinxsidebar a { background-color: #ceccca; padding: 3px; } + + #ns3_home1 img { + background-color: transparent; + } + + img.footer { + background-color: transparent; + } + + #nav-sync img { + background-color: transparent; + } } diff --git a/doc/tutorial/pickle-to-xml.py b/doc/tutorial/pickle-to-xml.py index 6a4fcebb3..9ba8ac6b3 100755 --- a/doc/tutorial/pickle-to-xml.py +++ b/doc/tutorial/pickle-to-xml.py @@ -7,35 +7,41 @@ # ... # -import pickle -import os import codecs +import os +import pickle + def dump_pickles(out, dirname, filename, path): - with open(os.path.join(dirname, filename), 'r', encoding='utf-8') as f: + with open(os.path.join(dirname, filename), "r", encoding="utf-8") as f: data = pickle.load(f) - with codecs.open(data['current_page_name'] + '.frag', mode='w', encoding='utf-8') as fragment_file: - fragment_file.write(data['body']) + with codecs.open( + data["current_page_name"] + ".frag", mode="w", encoding="utf-8" + ) as fragment_file: + fragment_file.write(data["body"]) out.write(' \n' % path) - out.write(' %s.frag\n' % data['current_page_name']) - if data['prev'] is not None: - out.write(' %s\n' % - (os.path.normpath(os.path.join(path, data['prev']['link'])), - data['prev']['title'])) - if data['next'] is not None: - out.write(' %s\n' % - (os.path.normpath(os.path.join(path, data['next']['link'])), - data['next']['title'])) - out.write(' \n') + out.write(" %s.frag\n" % data["current_page_name"]) + if data["prev"] is not None: + out.write( + ' %s\n' + % (os.path.normpath(os.path.join(path, data["prev"]["link"])), data["prev"]["title"]) + ) + if data["next"] is not None: + out.write( + ' %s\n' + % (os.path.normpath(os.path.join(path, data["next"]["link"])), data["next"]["title"]) + ) + out.write(" \n") - if data['next'] is not None: - next_path = os.path.normpath(os.path.join(path, data['next']['link'])) - next_filename = os.path.basename(next_path) + '.fpickle' + if data["next"] is not None: + next_path = os.path.normpath(os.path.join(path, data["next"]["link"])) + next_filename = os.path.basename(next_path) + ".fpickle" dump_pickles(out, dirname, next_filename, next_path) + import sys -sys.stdout.write('\n') -dump_pickles(sys.stdout, os.path.dirname(sys.argv[1]), os.path.basename(sys.argv[1]), '/') -sys.stdout.write('') +sys.stdout.write("\n") +dump_pickles(sys.stdout, os.path.dirname(sys.argv[1]), os.path.basename(sys.argv[1]), "/") +sys.stdout.write("") diff --git a/doc/tutorial/source/conf.py b/doc/tutorial/source/conf.py index a93ff993f..c1a46d4c2 100644 --- a/doc/tutorial/source/conf.py +++ b/doc/tutorial/source/conf.py @@ -24,15 +24,15 @@ # Tip from https://stackoverflow.com/questions/9899283/how-do-you-change-the-code-example-font-size-in-latex-pdf-output-with-sphinx/9955928 # Note: sizes are \footnotesize (8pt), \small (9pt), and \normalsize (10pt). -#from sphinx.highlighting import PygmentsBridge -#from pygments.formatters.latex import LatexFormatter +# from sphinx.highlighting import PygmentsBridge +# from pygments.formatters.latex import LatexFormatter # -#class CustomLatexFormatter(LatexFormatter): +# class CustomLatexFormatter(LatexFormatter): # def __init__(self, **options): # super(CustomLatexFormatter, self).__init__(**options) # self.verboptions = r"formatcom=\footnotesize" # -#PygmentsBridge.latex_formatter = CustomLatexFormatter +# PygmentsBridge.latex_formatter = CustomLatexFormatter # -- General configuration ------------------------------------------------ @@ -43,37 +43,37 @@ # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. -extensions = ['sphinx.ext.imgmath'] +extensions = ["sphinx.ext.imgmath"] # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # # source_suffix = ['.rst', '.md'] -source_suffix = '.rst' +source_suffix = ".rst" # The encoding of source files. # # source_encoding = 'utf-8-sig' # The master toctree document. -master_doc = 'index' +master_doc = "index" # General information about the project. -project = u'ns-3 project' -copyright = u'2006-2019' -#author = u'test' +project = "ns-3 project" +copyright = "2006-2019, ns-3 project" +# author = u'test' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. -version = u'ns-3.40' +version = "ns-3.41" # The full version, including alpha/beta/rc tags. -release = u'ns-3.40' +release = "ns-3.41" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -94,7 +94,7 @@ language = None # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # These patterns also affect html_static_path and html_extra_path -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] # The reST default role (used for this markup: `text`) to use for all # documents. @@ -116,7 +116,7 @@ exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] # show_authors = False # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +pygments_style = "sphinx" # A list of ignored prefixes for module index sorting. # modindex_common_prefix = [] @@ -133,7 +133,7 @@ todo_include_todos = False # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -html_theme = 'ns3_html_theme' +html_theme = "ns3_html_theme" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the @@ -142,13 +142,13 @@ html_theme = 'ns3_html_theme' # html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. -html_theme_path = ['../..'] +html_theme_path = ["../.."] # The name for this set of Sphinx documents. # " v documentation" by default. # # html_title = 'est vtest' -html_title = 'Tutorial' +html_title = "Tutorial" # A shorter title for the navigation bar. Default is the same as html_title. # @@ -168,7 +168,7 @@ html_title = 'Tutorial' # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_static_path = ["_static"] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied @@ -180,7 +180,7 @@ html_static_path = ['_static'] # bottom, using the given strftime format. # The empty string is equivalent to '%b %d, %Y'. # -html_last_updated_fmt = '%b %d, %Y %H:%M' +html_last_updated_fmt = "%b %d, %Y %H:%M" # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. @@ -248,7 +248,7 @@ html_last_updated_fmt = '%b %d, %Y %H:%M' # html_search_scorer = 'scorer.js' # Output file base name for HTML help builder. -htmlhelp_basename = 'ns-3doc' +htmlhelp_basename = "ns-3doc" # -- Options for LaTeX output --------------------------------------------- @@ -256,11 +256,9 @@ latex_elements = { # The paper size ('letterpaper' or 'a4paper'). # # 'papersize': 'letterpaper', - # The font size ('10pt', '11pt' or '12pt'). # # 'pointsize': '10pt', - # Additional stuff for the LaTeX preamble. # # VerbatimBorderColor: make the box around code samples blend into the background @@ -273,10 +271,10 @@ latex_elements = { # See above to change the font size of verbatim code blocks # # 'preamble': '', - 'preamble': u'''\\usepackage{amssymb} + "preamble": """\\usepackage{amssymb} \\definecolor{VerbatimBorderColor}{rgb}{1,1,1} \\renewcommand{\\sphinxcode}[1]{\\texttt{\\small{#1}}} -''' +""" # Latex figure (float) alignment # # 'figure_align': 'htbp', @@ -286,14 +284,13 @@ latex_elements = { # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - ('index', 'ns-3-tutorial.tex', u'ns-3 Tutorial', - u'ns-3 project', 'manual'), + ("index", "ns-3-tutorial.tex", "ns-3 Tutorial", "ns-3 project", "manual"), ] # The name of an image file (relative to this directory) to place at the top of # the title page. # -latex_logo = '../../ns3_html_theme/static/ns-3.png' +latex_logo = "../../ns3_html_theme/static/ns-3.png" # If true, show page references after internal links. # @@ -322,10 +319,7 @@ latex_logo = '../../ns3_html_theme/static/ns-3.png' # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [ - ('index', 'ns-3-tutorial', u'ns-3 Tutorial', - [u'ns-3 project'], 1) -] +man_pages = [("index", "ns-3-tutorial", "ns-3 Tutorial", ["ns-3 project"], 1)] # If true, show URL addresses after external links. # @@ -333,11 +327,11 @@ man_pages = [ # -- Options for texinfo output --------------------------------------- -#texinfo_documents = [ +# texinfo_documents = [ # (master_doc, 'test', u'test Documentation', # author, 'test', 'One line description of project.', # 'Miscellaneous'), -#] +# ] # Documents to append as an appendix to all manuals. # diff --git a/doc/tutorial/source/getting-started.rst b/doc/tutorial/source/getting-started.rst index c393b9020..512102b0d 100644 --- a/doc/tutorial/source/getting-started.rst +++ b/doc/tutorial/source/getting-started.rst @@ -61,7 +61,7 @@ the project provides an installation guide for various systems, available at https://www.nsnam.org/docs/installation/html/index.html. -As of the most recent |ns3| release (ns-3.40), the following tools +As of the most recent |ns3| release (ns-3.41), the following tools are needed to get started with |ns3|: ============ =========================================================== @@ -69,7 +69,7 @@ Prerequisite Package/version ============ =========================================================== C++ compiler ``clang++`` or ``g++`` (g++ version 9 or greater) Python ``python3`` version >=3.6 -CMake ``cmake`` version >=3.10 +CMake ``cmake`` version >=3.13 Build system ``make``, ``ninja``, ``xcodebuild`` (XCode) Git any recent version (to access |ns3| from `GitLab.com `_) tar any recent version (to unpack an `ns-3 release `_) @@ -116,21 +116,21 @@ get a copy of a release by typing the following into your Linux shell $ cd $ mkdir workspace $ cd workspace - $ wget https://www.nsnam.org/release/ns-allinone-3.40.tar.bz2 - $ tar xjf ns-allinone-3.40.tar.bz2 + $ wget https://www.nsnam.org/release/ns-allinone-3.41.tar.bz2 + $ tar xjf ns-allinone-3.41.tar.bz2 Notice the use above of the ``wget`` utility, which is a command-line tool to fetch objects from the web; if you do not have this installed, you can use a browser for this step. Following these steps, if you change into the directory -``ns-allinone-3.40``, you should see a number of files and directories +``ns-allinone-3.41``, you should see a number of files and directories .. sourcecode:: text - $ cd ns-allinone-3.40 + $ cd ns-allinone-3.41 $ ls - bake build.py constants.py netanim-3.109 ns-3.40 README.md util.py + bake build.py constants.py netanim-3.109 ns-3.41 README.md util.py You are now ready to build the base |ns3| distribution and may skip ahead to the section on building |ns3|. @@ -180,7 +180,7 @@ release number: .. sourcecode:: console - $ python3 download.py -n ns-3.40 + $ python3 download.py -n ns-3.41 After this step, the additional repositories of |ns3|, bake, pybindgen, and netanim will be downloaded to the ``ns-3-allinone`` directory. @@ -249,9 +249,9 @@ distribution of your choice. There are a few configuration targets available: -1. ``ns-3.40``: the code corresponding to the release +1. ``ns-3.41``: the code corresponding to the release 2. ``ns-3-dev``: a similar module but using the development code tree -3. ``ns-allinone-3.40``: the module that includes other optional features +3. ``ns-allinone-3.41``: the module that includes other optional features such as bake build system, netanim animator, and pybindgen 4. ``ns-3-allinone``: similar to the released version of the allinone module, but for development code. @@ -268,7 +268,7 @@ code either by inspection of the repository list or by going to the `"ns-3 Releases" `_ web page and clicking on the latest release link. We'll proceed in -this tutorial example with ``ns-3.40``. +this tutorial example with ``ns-3.41``. We are now going to use the bake tool to pull down the various pieces of |ns3| you will be using. First, we'll say a word about running bake. @@ -297,7 +297,7 @@ Step into the workspace directory and type the following into your shell: .. sourcecode:: console - $ ./bake.py configure -e ns-allinone-3.40 + $ ./bake.py configure -e ns-allinone-3.41 Next, we'll ask bake to check whether we have enough tools to download various components. Type: @@ -347,7 +347,7 @@ should yield something like: >> Downloading click-ns-3.37 - OK >> Downloading BRITE - OK >> Downloading openflow-dev - OK - >> Downloading ns-3.40 (target directory:ns-3.40) - OK + >> Downloading ns-3.41 (target directory:ns-3.41) - OK The above suggests that three sources have been downloaded. Check the ``source`` directory now and type ``ls``; one should see: @@ -356,7 +356,7 @@ The above suggests that three sources have been downloaded. Check the $ cd source $ ls - BRITE click-ns-3.37 netanim-3.109 ns-3.40 openflow-dev + BRITE click-ns-3.37 netanim-3.109 ns-3.41 openflow-dev You are now ready to build the |ns3| distribution. @@ -386,7 +386,7 @@ native |ns3| build system, CMake, to be introduced later in this tutorial. If you downloaded using a tarball you should have a directory called something like -``ns-allinone-3.40`` under your ``~/workspace`` directory. +``ns-allinone-3.41`` under your ``~/workspace`` directory. Type the following: .. sourcecode:: console @@ -419,7 +419,7 @@ and you should see something like: .. sourcecode:: text >> Building netanim-3.109 - OK - >> Building ns-3.40 - OK + >> Building ns-3.41 - OK There may be failures to build all components, but the build will proceed anyway if the component is optional. @@ -1146,6 +1146,65 @@ You can open the source files you want, put some breakpoints and then click debu .. figure:: ../figures/vscode/debugging.png +Note: If you are running on Windows, you need to manually add your ns-3 library directory +to the ``PATH`` environment variable. This can be accomplished in two ways. + +The first, is to set VSCode's ``settings.json`` file to include the following: + +.. sourcecode:: json + + "cmake.environment": { + "PATH": "${env:PATH};${workspaceFolder}/build/lib" + } + +The second, a more permanent solution, with the following command: + +.. sourcecode:: terminal + + > echo %PATH% + C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem; + C:\Windows\System32\OpenSSH\;C:\Program Files\dotnet\;C:\Program Files\PuTTY\;C:\Program Files\VSCodium\bin; + C:\Program Files\Meld\;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\system32;C:\Windows; + C:\Windows\System32\Wbem;C:\Windows\System32\OpenSSH\;C:\Program Files\dotnet\;C:\Program Files\PuTTY\; + C:\Program Files\VSCodium\bin;C:\Program Files\Meld\;C:\Users\username\AppData\Local\Microsoft\WindowsApps; + + > setx PATH "%PATH%;C:\path\to\ns-3-dev\build\lib" + + SUCCESS: Specified value was saved. + + > echo %PATH% + C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem; + ... + C:\Program Files\VSCodium\bin;C:\Program Files\Meld\;C:\Users\username\AppData\Local\Microsoft\WindowsApps; + C:\tools\source\ns-3-dev\build\lib; + +If you do not setup your ``PATH`` environment variable, you may end up having problems to debug that +look like the following: + +.. sourcecode:: console + + =thread-group-added,id="i1" + GNU gdb (GDB) 14.1 + Copyright (C) 2023 Free Software Foundation, Inc. + License GPLv3+: GNU GPL version 3 or later + ... + ERROR: Unable to start debugging. GDB exited unexpectedly. + The program 'C:\tools\source\ns-3-dev\build\examples\wireless\ns3-dev-wifi-he-network-debug.exe' has exited with code 0 (0x00000000). + + ERROR: During startup program exited with code 0xc0000135. + +Or + +.. sourcecode:: console + + =thread-group-added,id="i1" + GNU gdb (GDB) 14.1 + Copyright (C) 2023 Free Software Foundation, Inc. + License GPLv3+: GNU GPL version 3 or later + ... + ERROR: Unable to start debugging. Unexpected GDB output from command "-exec-run". During startup program exited with code 0xc0000135. + The program 'C:\tools\source\ns-3-dev\build\examples\wireless\ns3-dev-wifi-he-network-debug.exe' has exited with code 0 (0x00000000). + JetBrains CLion =============== diff --git a/doc/tutorial/source/index.rst b/doc/tutorial/source/index.rst index 8af2593b1..758446e6b 100644 --- a/doc/tutorial/source/index.rst +++ b/doc/tutorial/source/index.rst @@ -8,7 +8,7 @@ follows: * Several guides that are version controlled for each release (the `latest release `_) and - `development tree `_: + `development tree `_: * Tutorial *(this document)* * Installation Guide diff --git a/doc/tutorial/source/quick-start.rst b/doc/tutorial/source/quick-start.rst index 6c072d173..9c3f22329 100644 --- a/doc/tutorial/source/quick-start.rst +++ b/doc/tutorial/source/quick-start.rst @@ -64,13 +64,13 @@ Downloading the Latest Release :: - $ tar xjf ns-allinone-3.40.tar.bz2 + $ tar xjf ns-allinone-3.41.tar.bz2 3) Change into the |ns3| directory directly; e.g. :: - $ cd ns-allinone-3.40/ns-3.40 + $ cd ns-allinone-3.41/ns-3.41 The ns-allinone directory has some additional components but we are skipping over them here; one can work directly from the |ns3| source code directory. @@ -92,12 +92,12 @@ only to `cd` into ns-3-dev; the `master` branch is checked out by default. $ cd ns-3-dev -If instead you want to try the most recent release (version 3.40 as of this +If instead you want to try the most recent release (version 3.41 as of this writing), you can checkout a branch corresponding to that git tag: :: - $ git checkout -b ns-3.40-branch ns-3.40 + $ git checkout -b ns-3.41-branch ns-3.41 Building and testing ns-3 ************************* diff --git a/doc/tutorial/source/tracing.rst b/doc/tutorial/source/tracing.rst index d55f12f5d..dfd397eca 100644 --- a/doc/tutorial/source/tracing.rst +++ b/doc/tutorial/source/tracing.rst @@ -558,7 +558,7 @@ could have used this ``Ptr`` to call a Connect method directly:: Ptr theObject = wifiStaNodes.Get(nWifi - 1); - theObject->TraceConnectWithoutContext("CourseChange", MakeCallback(&CourseChange)); + theObject->GetObject()->TraceConnectWithoutContext("CourseChange", MakeCallback(&CourseChange)); In the ``third.cc`` example, we actually wanted an additional "context" to be delivered along with the Callback parameters (which will be @@ -566,7 +566,7 @@ explained below) so we could actually use the following equivalent code:: Ptr theObject = wifiStaNodes.Get(nWifi - 1); - theObject->TraceConnect("CourseChange", MakeCallback(&CourseChange)); + theObject->GetObject()->TraceConnect("CourseChange", MakeCallback(&CourseChange)); It turns out that the internal code for ``Config::ConnectWithoutContext`` and ``Config::Connect`` actually diff --git a/examples/channel-models/three-gpp-v2v-channel-example.cc b/examples/channel-models/three-gpp-v2v-channel-example.cc index 682cdb8fe..783077656 100644 --- a/examples/channel-models/three-gpp-v2v-channel-example.cc +++ b/examples/channel-models/three-gpp-v2v-channel-example.cc @@ -114,11 +114,12 @@ ComputeSnr(const ComputeSnrParams& params) *(params.txParams->psd) *= propagationGainLinear; // apply the fast fading and the beamforming gain - Ptr rxPsd = m_spectrumLossModel->CalcRxPowerSpectralDensity(params.txParams, - params.txMob, - params.rxMob, - params.txAntenna, - params.rxAntenna); + auto rxParams = m_spectrumLossModel->CalcRxPowerSpectralDensity(params.txParams, + params.txMob, + params.rxMob, + params.txAntenna, + params.rxAntenna); + Ptr rxPsd = rxParams->psd; NS_LOG_DEBUG("Average rx power " << 10 * log10(Sum(*rxPsd) * 180e3) << " dB"); // create the noise psd diff --git a/examples/energy/energy-model-example.cc b/examples/energy/energy-model-example.cc index a59b043c5..97e656687 100644 --- a/examples/energy/energy-model-example.cc +++ b/examples/energy/energy-model-example.cc @@ -17,7 +17,6 @@ * Author: Sidharth Nabar , He Wu */ -#include "ns3/config-store-module.h" #include "ns3/core-module.h" #include "ns3/energy-module.h" #include "ns3/internet-module.h" diff --git a/examples/energy/energy-model-with-harvesting-example.cc b/examples/energy/energy-model-with-harvesting-example.cc index 4ee5639a8..93dfa393f 100644 --- a/examples/energy/energy-model-with-harvesting-example.cc +++ b/examples/energy/energy-model-with-harvesting-example.cc @@ -46,7 +46,6 @@ * */ -#include "ns3/config-store-module.h" #include "ns3/core-module.h" #include "ns3/energy-module.h" #include "ns3/internet-module.h" diff --git a/examples/naming/object-names.cc b/examples/naming/object-names.cc index 1238ade94..f52678eca 100644 --- a/examples/naming/object-names.cc +++ b/examples/naming/object-names.cc @@ -217,7 +217,7 @@ main(int argc, char* argv[]) if (!outputValidated) { std::cerr << "Program internal checking failed; returning with error" << std::endl; - return (1); + return 1; } return 0; diff --git a/examples/realtime/realtime-udp-echo.py b/examples/realtime/realtime-udp-echo.py index a90bb6423..494d616ed 100644 --- a/examples/realtime/realtime-udp-echo.py +++ b/examples/realtime/realtime-udp-echo.py @@ -23,89 +23,101 @@ # - DropTail queues # - Tracing of queues and packet receptions to file "udp-echo.tr" -from ns import ns +try: + from ns import ns +except ModuleNotFoundError: + raise SystemExit( + "Error: ns3 Python module not found;" + " Python bindings may not be enabled" + " or your PYTHONPATH might not be properly configured" + ) + def main(argv): - # - # Allow the user to override any of the defaults and the above Bind() at - # run-time, via command-line arguments - # - cmd = ns.core.CommandLine() - cmd.Parse(argv) + # + # Allow the user to override any of the defaults and the above Bind() at + # run-time, via command-line arguments + # + cmd = ns.core.CommandLine() + cmd.Parse(argv) - # - # But since this is a realtime script, don't allow the user to mess with - # that. - # - ns.core.GlobalValue.Bind("SimulatorImplementationType", ns.core.StringValue("ns3::RealtimeSimulatorImpl")) + # + # But since this is a realtime script, don't allow the user to mess with + # that. + # + ns.core.GlobalValue.Bind( + "SimulatorImplementationType", ns.core.StringValue("ns3::RealtimeSimulatorImpl") + ) - # - # Explicitly create the nodes required by the topology (shown above). - # - print ("Create nodes.") - n = ns.network.NodeContainer() - n.Create(4) + # + # Explicitly create the nodes required by the topology (shown above). + # + print("Create nodes.") + n = ns.network.NodeContainer() + n.Create(4) - internet = ns.internet.InternetStackHelper() - internet.Install(n) + internet = ns.internet.InternetStackHelper() + internet.Install(n) - # - # Explicitly create the channels required by the topology (shown above). - # - print ("Create channels.") - csma = ns.csma.CsmaHelper() - csma.SetChannelAttribute("DataRate", ns.network.DataRateValue(ns.network.DataRate(5000000))) - csma.SetChannelAttribute("Delay", ns.core.TimeValue(ns.core.MilliSeconds(2))); - csma.SetDeviceAttribute("Mtu", ns.core.UintegerValue(1400)) - d = csma.Install(n) + # + # Explicitly create the channels required by the topology (shown above). + # + print("Create channels.") + csma = ns.csma.CsmaHelper() + csma.SetChannelAttribute("DataRate", ns.network.DataRateValue(ns.network.DataRate(5000000))) + csma.SetChannelAttribute("Delay", ns.core.TimeValue(ns.core.MilliSeconds(2))) + csma.SetDeviceAttribute("Mtu", ns.core.UintegerValue(1400)) + d = csma.Install(n) - # - # We've got the "hardware" in place. Now we need to add IP addresses. - # - print ("Assign IP Addresses.") - ipv4 = ns.internet.Ipv4AddressHelper() - ipv4.SetBase(ns.network.Ipv4Address("10.1.1.0"), ns.network.Ipv4Mask("255.255.255.0")) - i = ipv4.Assign(d) + # + # We've got the "hardware" in place. Now we need to add IP addresses. + # + print("Assign IP Addresses.") + ipv4 = ns.internet.Ipv4AddressHelper() + ipv4.SetBase(ns.network.Ipv4Address("10.1.1.0"), ns.network.Ipv4Mask("255.255.255.0")) + i = ipv4.Assign(d) - print ("Create Applications.") + print("Create Applications.") - # - # Create a UdpEchoServer application on node one. - # - port = 9 # well-known echo port number - server = ns.applications.UdpEchoServerHelper(port) - apps = server.Install(n.Get(1)) - apps.Start(ns.core.Seconds(1.0)) - apps.Stop(ns.core.Seconds(10.0)) + # + # Create a UdpEchoServer application on node one. + # + port = 9 # well-known echo port number + server = ns.applications.UdpEchoServerHelper(port) + apps = server.Install(n.Get(1)) + apps.Start(ns.core.Seconds(1.0)) + apps.Stop(ns.core.Seconds(10.0)) - # - # Create a UdpEchoClient application to send UDP datagrams from node zero to - # node one. - # - packetSize = 1024 - maxPacketCount = 500 - interPacketInterval = ns.core.Seconds(0.01) - client = ns.applications.UdpEchoClientHelper(i.GetAddress(1).ConvertTo(), port) - client.SetAttribute("MaxPackets", ns.core.UintegerValue(maxPacketCount)) - client.SetAttribute("Interval", ns.core.TimeValue(interPacketInterval)) - client.SetAttribute("PacketSize", ns.core.UintegerValue(packetSize)) - apps = client.Install(n.Get(0)) - apps.Start(ns.core.Seconds(2.0)) - apps.Stop(ns.core.Seconds(10.0)) + # + # Create a UdpEchoClient application to send UDP datagrams from node zero to + # node one. + # + packetSize = 1024 + maxPacketCount = 500 + interPacketInterval = ns.core.Seconds(0.01) + client = ns.applications.UdpEchoClientHelper(i.GetAddress(1).ConvertTo(), port) + client.SetAttribute("MaxPackets", ns.core.UintegerValue(maxPacketCount)) + client.SetAttribute("Interval", ns.core.TimeValue(interPacketInterval)) + client.SetAttribute("PacketSize", ns.core.UintegerValue(packetSize)) + apps = client.Install(n.Get(0)) + apps.Start(ns.core.Seconds(2.0)) + apps.Stop(ns.core.Seconds(10.0)) - ascii = ns.network.AsciiTraceHelper() - csma.EnableAsciiAll(ascii.CreateFileStream("realtime-udp-echo.tr")) - csma.EnablePcapAll("realtime-udp-echo", False) + ascii = ns.network.AsciiTraceHelper() + csma.EnableAsciiAll(ascii.CreateFileStream("realtime-udp-echo.tr")) + csma.EnablePcapAll("realtime-udp-echo", False) - # - # Now, do the actual simulation. - # - print ("Run Simulation.") - ns.core.Simulator.Stop(ns.Seconds(10)) - ns.core.Simulator.Run() - ns.core.Simulator.Destroy() - print ("Done.") + # + # Now, do the actual simulation. + # + print("Run Simulation.") + ns.core.Simulator.Stop(ns.Seconds(10)) + ns.core.Simulator.Run() + ns.core.Simulator.Destroy() + print("Done.") -if __name__ == '__main__': - import sys - main(sys.argv) + +if __name__ == "__main__": + import sys + + main(sys.argv) diff --git a/examples/routing/simple-routing-ping6.py b/examples/routing/simple-routing-ping6.py index f14d521d8..501cfb13e 100644 --- a/examples/routing/simple-routing-ping6.py +++ b/examples/routing/simple-routing-ping6.py @@ -27,7 +27,14 @@ # router # -from ns import ns +try: + from ns import ns +except ModuleNotFoundError: + raise SystemExit( + "Error: ns3 Python module not found;" + " Python bindings may not be enabled" + " or your PYTHONPATH might not be properly configured" + ) def main(argv): @@ -73,7 +80,7 @@ def main(argv): print("Application") packetSize = 1024 maxPacketCount = 5 - interPacketInterval = ns.Seconds(1.) + interPacketInterval = ns.Seconds(1.0) # ping = ns.PingHelper(i2.GetAddress(1, 1).ConvertTo()) ping = ns.PingHelper(i2.GetAddress(1, 1).ConvertTo()) @@ -98,7 +105,7 @@ def main(argv): ns.Simulator.Destroy() -if __name__ == '__main__': +if __name__ == "__main__": import sys main(sys.argv) diff --git a/examples/tcp/examples-to-run.py b/examples/tcp/examples-to-run.py index fd2b27824..9a4505850 100644 --- a/examples/tcp/examples-to-run.py +++ b/examples/tcp/examples-to-run.py @@ -11,10 +11,26 @@ cpp_examples = [ ("tcp-large-transfer", "True", "True"), ("tcp-star-server", "True", "True"), ("tcp-variants-comparison", "True", "True"), - ("tcp-validation --firstTcpType=dctcp --linkRate=50Mbps --baseRtt=10ms --queueUseEcn=1 --stopTime=15s --validate=dctcp-10ms", "True", "True"), - ("tcp-validation --firstTcpType=dctcp --linkRate=50Mbps --baseRtt=80ms --queueUseEcn=1 --stopTime=40s --validate=dctcp-80ms", "True", "True"), - ("tcp-validation --firstTcpType=cubic --linkRate=50Mbps --baseRtt=50ms --queueUseEcn=0 --stopTime=20s --validate=cubic-50ms-no-ecn", "True", "True"), - ("tcp-validation --firstTcpType=cubic --linkRate=50Mbps --baseRtt=50ms --queueUseEcn=1 --stopTime=20s --validate=cubic-50ms-ecn", "True", "True"), + ( + "tcp-validation --firstTcpType=dctcp --linkRate=50Mbps --baseRtt=10ms --queueUseEcn=1 --stopTime=15s --validate=dctcp-10ms", + "True", + "True", + ), + ( + "tcp-validation --firstTcpType=dctcp --linkRate=50Mbps --baseRtt=80ms --queueUseEcn=1 --stopTime=40s --validate=dctcp-80ms", + "True", + "True", + ), + ( + "tcp-validation --firstTcpType=cubic --linkRate=50Mbps --baseRtt=50ms --queueUseEcn=0 --stopTime=20s --validate=cubic-50ms-no-ecn", + "True", + "True", + ), + ( + "tcp-validation --firstTcpType=cubic --linkRate=50Mbps --baseRtt=50ms --queueUseEcn=1 --stopTime=20s --validate=cubic-50ms-ecn", + "True", + "True", + ), ] # A list of Python examples to run in order to ensure that they remain diff --git a/examples/tcp/tcp-bbr-example.cc b/examples/tcp/tcp-bbr-example.cc index 6c027a5e4..729c4b3fa 100644 --- a/examples/tcp/tcp-bbr-example.cc +++ b/examples/tcp/tcp-bbr-example.cc @@ -60,9 +60,15 @@ #include "ns3/point-to-point-module.h" #include "ns3/traffic-control-module.h" +#include + using namespace ns3; +using namespace ns3::SystemPath; std::string dir; +std::ofstream throughput; +std::ofstream queueSize; + uint32_t prev = 0; Time prevTime = Seconds(0); @@ -71,15 +77,16 @@ static void TraceThroughput(Ptr monitor) { FlowMonitor::FlowStatsContainer stats = monitor->GetFlowStats(); - auto itr = stats.begin(); - Time curTime = Now(); - std::ofstream thr(dir + "/throughput.dat", std::ios::out | std::ios::app); - thr << curTime << " " - << 8 * (itr->second.txBytes - prev) / - (1000 * 1000 * (curTime.GetSeconds() - prevTime.GetSeconds())) - << std::endl; - prevTime = curTime; - prev = itr->second.txBytes; + if (!stats.empty()) + { + auto itr = stats.begin(); + Time curTime = Now(); + throughput << curTime << " " + << 8 * (itr->second.txBytes - prev) / ((curTime - prevTime).ToDouble(Time::US)) + << std::endl; + prevTime = curTime; + prev = itr->second.txBytes; + } Simulator::Schedule(Seconds(0.2), &TraceThroughput, monitor); } @@ -89,9 +96,7 @@ CheckQueueSize(Ptr qd) { uint32_t qsize = qd->GetCurrentSize().GetValue(); Simulator::Schedule(Seconds(0.2), &CheckQueueSize, qd); - std::ofstream q(dir + "/queueSize.dat", std::ios::out | std::ios::app); - q << Simulator::Now().GetSeconds() << " " << qsize << std::endl; - q.close(); + queueSize << Simulator::Now().GetSeconds() << " " << qsize << std::endl; } // Trace congestion window @@ -143,6 +148,10 @@ main(int argc, char* argv[]) queueDisc = std::string("ns3::") + queueDisc; Config::SetDefault("ns3::TcpL4Protocol::SocketType", StringValue("ns3::" + tcpTypeId)); + + // The maximum send buffer size is set to 4194304 bytes (4MB) and the + // maximum receive buffer size is set to 6291456 bytes (6MB) in the Linux + // kernel. The same buffer sizes are used as default in this example. Config::SetDefault("ns3::TcpSocket::SndBufSize", UintegerValue(4194304)); Config::SetDefault("ns3::TcpSocket::RcvBufSize", UintegerValue(6291456)); Config::SetDefault("ns3::TcpSocket::InitialCwnd", UintegerValue(10)); @@ -225,23 +234,20 @@ main(int argc, char* argv[]) // Create a new directory to store the output of the program dir = "bbr-results/" + currentTime + "/"; - std::string dirToSave = "mkdir -p " + dir; - if (system(dirToSave.c_str()) == -1) - { - exit(1); - } + MakeDirectories(dir); // The plotting scripts are provided in the following repository, if needed: // https://github.com/mohittahiliani/BBR-Validation/ // // Download 'PlotScripts' directory (which is inside ns-3 scripts directory) // from the link given above and place it in the ns-3 root directory. - // Uncomment the following three lines to generate plots for Congestion - // Window, sender side throughput and queue occupancy on the bottleneck link. + // Uncomment the following three lines to copy plot scripts for + // Congestion Window, sender side throughput and queue occupancy on the + // bottleneck link into the output directory. // - // system (("cp -R PlotScripts/gnuplotScriptCwnd " + dir).c_str ()); - // system (("cp -R PlotScripts/gnuplotScriptThroughput " + dir).c_str ()); - // system (("cp -R PlotScripts/gnuplotScriptQueueSize " + dir).c_str ()); + // std::filesystem::copy("PlotScripts/gnuplotScriptCwnd", dir); + // std::filesystem::copy("PlotScripts/gnuplotScriptThroughput", dir); + // std::filesystem::copy("PlotScripts/gnuplotScriptQueueSize", dir); // Trace the queue occupancy on the second interface of R1 tch.Uninstall(routers.Get(0)->GetDevice(1)); @@ -252,13 +258,17 @@ main(int argc, char* argv[]) // Generate PCAP traces if it is enabled if (enablePcap) { - if (system((dirToSave + "/pcap/").c_str()) == -1) - { - exit(1); - } + MakeDirectories(dir + "pcap/"); bottleneckLink.EnablePcapAll(dir + "/pcap/bbr", true); } + // Open files for writing throughput traces and queue size + throughput.open(dir + "/throughput.dat", std::ios::out); + queueSize.open(dir + "/queueSize.dat", std::ios::out); + + NS_ASSERT_MSG(throughput.is_open(), "Throughput file was not opened correctly"); + NS_ASSERT_MSG(queueSize.is_open(), "Queue size file was not opened correctly"); + // Check for dropped packets using Flow Monitor FlowMonitorHelper flowmon; Ptr monitor = flowmon.InstallAll(); @@ -268,5 +278,8 @@ main(int argc, char* argv[]) Simulator::Run(); Simulator::Destroy(); + throughput.close(); + queueSize.close(); + return 0; } diff --git a/examples/tcp/tcp-linux-reno.cc b/examples/tcp/tcp-linux-reno.cc index 96978f00c..85bbcde9c 100644 --- a/examples/tcp/tcp-linux-reno.cc +++ b/examples/tcp/tcp-linux-reno.cc @@ -52,6 +52,9 @@ std::string dir = "results/"; Time stopTime = Seconds(60); uint32_t segmentSize = 524; +std::ofstream fPlotQueue; +std::ofstream fPlotCwnd; + // Function to check queue length of Router 1 void CheckQueueSize(Ptr queue) @@ -60,19 +63,14 @@ CheckQueueSize(Ptr queue) // Check queue size every 1/100 of a second Simulator::Schedule(Seconds(0.001), &CheckQueueSize, queue); - std::ofstream fPlotQueue(std::stringstream(dir + "queue-size.dat").str(), - std::ios::out | std::ios::app); fPlotQueue << Simulator::Now().GetSeconds() << " " << qSize << std::endl; - fPlotQueue.close(); } // Function to trace change in cwnd at n0 static void CwndChange(uint32_t oldCwnd, uint32_t newCwnd) { - std::ofstream fPlotQueue(dir + "cwndTraces/n0.dat", std::ios::out | std::ios::app); - fPlotQueue << Simulator::Now().GetSeconds() << " " << newCwnd / segmentSize << std::endl; - fPlotQueue.close(); + fPlotCwnd << Simulator::Now().GetSeconds() << " " << newCwnd / segmentSize << std::endl; } // Function to calculate drops in a particular Queue @@ -228,15 +226,11 @@ main(int argc, char* argv[]) retVal = system(dirToRemove.c_str()); NS_ASSERT_MSG(retVal == 0, "Error in return value"); } - std::string dirToSave = "mkdir -p " + dir; - retVal = system(dirToSave.c_str()); - NS_ASSERT_MSG(retVal == 0, "Error in return value"); - retVal = system((dirToSave + "/pcap/").c_str()); - NS_ASSERT_MSG(retVal == 0, "Error in return value"); - retVal = system((dirToSave + "/queueTraces/").c_str()); - NS_ASSERT_MSG(retVal == 0, "Error in return value"); - retVal = system((dirToSave + "/cwndTraces/").c_str()); - NS_ASSERT_MSG(retVal == 0, "Error in return value"); + + SystemPath::MakeDirectories(dir); + SystemPath::MakeDirectories(dir + "/pcap/"); + SystemPath::MakeDirectories(dir + "/queueTraces/"); + SystemPath::MakeDirectories(dir + "/cwndTraces/"); // Set default parameters for queue discipline Config::SetDefault(qdiscTypeId + "::MaxSize", QueueSizeValue(QueueSize("100p"))); @@ -251,6 +245,10 @@ main(int argc, char* argv[]) // Enable BQL tch.SetQueueLimits("ns3::DynamicQueueLimits"); + // Open files for writing queue size and cwnd traces + fPlotQueue.open(dir + "queue-size.dat", std::ios::out); + fPlotCwnd.open(dir + "cwndTraces/n0.dat", std::ios::out); + // Calls function to check queue size Simulator::ScheduleNow(&CheckQueueSize, qd.Get(0)); @@ -299,5 +297,8 @@ main(int argc, char* argv[]) Simulator::Destroy(); + fPlotQueue.close(); + fPlotCwnd.close(); + return 0; } diff --git a/examples/tcp/tcp-validation.cc b/examples/tcp/tcp-validation.cc index b9a8c023d..18ee32031 100644 --- a/examples/tcp/tcp-validation.cc +++ b/examples/tcp/tcp-validation.cc @@ -663,6 +663,9 @@ main(int argc, char* argv[]) Config::SetDefault("ns3::TcpSocket::InitialCwnd", UintegerValue(10)); Config::SetDefault("ns3::TcpL4Protocol::RecoveryType", TypeIdValue(TcpPrrRecovery::GetTypeId())); + // Validation criteria were written for TCP Cubic without Reno-friendly behavior, so disable it + // for these tests + Config::SetDefault("ns3::TcpCubic::TcpFriendliness", BooleanValue(false)); //////////////////////////////////////////////////////////// // command-line argument parsing // diff --git a/examples/tutorial/first.py b/examples/tutorial/first.py index d3138bec8..42311ad2f 100644 --- a/examples/tutorial/first.py +++ b/examples/tutorial/first.py @@ -1,19 +1,26 @@ -# /* -# * 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 -# */ +# +# 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 +# -from ns import ns +try: + from ns import ns +except ModuleNotFoundError: + raise SystemExit( + "Error: ns3 Python module not found;" + " Python bindings may not be enabled" + " or your PYTHONPATH might not be properly configured" + ) # // Default Network Topology # // @@ -38,8 +45,7 @@ stack = ns.internet.InternetStackHelper() stack.Install(nodes) address = ns.internet.Ipv4AddressHelper() -address.SetBase(ns.network.Ipv4Address("10.1.1.0"), - ns.network.Ipv4Mask("255.255.255.0")) +address.SetBase(ns.network.Ipv4Address("10.1.1.0"), ns.network.Ipv4Mask("255.255.255.0")) interfaces = address.Assign(devices) @@ -61,4 +67,3 @@ clientApps.Stop(ns.core.Seconds(10.0)) ns.core.Simulator.Run() ns.core.Simulator.Destroy() - diff --git a/examples/tutorial/second.py b/examples/tutorial/second.py index e3ccaec11..0d01b9367 100644 --- a/examples/tutorial/second.py +++ b/examples/tutorial/second.py @@ -1,23 +1,30 @@ -# -*- Mode: Python; -*- -# /* -# * 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 -# * -# * Ported to Python by Mohit P. Tahiliani -# */ +# +# 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 +# +# Ported to Python by Mohit P. Tahiliani +# -from ns import ns +try: + from ns import ns +except ModuleNotFoundError: + raise SystemExit( + "Error: ns3 Python module not found;" + " Python bindings may not be enabled" + " or your PYTHONPATH might not be properly configured" + ) import sys +from ctypes import c_bool, c_int # // Default Network Topology # // @@ -27,7 +34,7 @@ import sys # // ================ # // LAN 10.1.2.0 -from ctypes import c_int, c_bool + nCsma = c_int(3) verbose = c_bool(True) cmd = ns.CommandLine(__file__) @@ -76,9 +83,11 @@ serverApps = echoServer.Install(csmaNodes.Get(nCsma.value)) serverApps.Start(ns.core.Seconds(1.0)) serverApps.Stop(ns.core.Seconds(10.0)) -echoClient = ns.applications.UdpEchoClientHelper(csmaInterfaces.GetAddress(nCsma.value).ConvertTo(), 9) +echoClient = ns.applications.UdpEchoClientHelper( + csmaInterfaces.GetAddress(nCsma.value).ConvertTo(), 9 +) echoClient.SetAttribute("MaxPackets", ns.core.UintegerValue(1)) -echoClient.SetAttribute("Interval", ns.core.TimeValue(ns.core.Seconds (1.0))) +echoClient.SetAttribute("Interval", ns.core.TimeValue(ns.core.Seconds(1.0))) echoClient.SetAttribute("PacketSize", ns.core.UintegerValue(1024)) clientApps = echoClient.Install(p2pNodes.Get(0)) @@ -88,8 +97,7 @@ clientApps.Stop(ns.core.Seconds(10.0)) ns.internet.Ipv4GlobalRoutingHelper.PopulateRoutingTables() pointToPoint.EnablePcapAll("second") -csma.EnablePcap ("second", csmaDevices.Get (1), True) +csma.EnablePcap("second", csmaDevices.Get(1), True) ns.core.Simulator.Run() ns.core.Simulator.Destroy() - diff --git a/examples/tutorial/third.py b/examples/tutorial/third.py index 6fad4e55e..fdc6b2133 100644 --- a/examples/tutorial/third.py +++ b/examples/tutorial/third.py @@ -1,23 +1,30 @@ -# -*- Mode: Python; -*- -# /* -# * 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 -# * -# * Ported to Python by Mohit P. Tahiliani -# */ +# +# 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 +# +# Ported to Python by Mohit P. Tahiliani +# -from ns import ns +try: + from ns import ns +except ModuleNotFoundError: + raise SystemExit( + "Error: ns3 Python module not found;" + " Python bindings may not be enabled" + " or your PYTHONPATH might not be properly configured" + ) import sys +from ctypes import c_bool, c_int # // Default Network Topology # // @@ -30,7 +37,7 @@ import sys # // ================ # // LAN 10.1.2.0 -from ctypes import c_bool, c_int + nCsma = c_int(3) verbose = c_bool(True) nWifi = c_int(3) @@ -83,22 +90,40 @@ phy = ns.wifi.YansWifiPhyHelper() phy.SetChannel(channel.Create()) mac = ns.wifi.WifiMacHelper() -ssid = ns.wifi.Ssid ("ns-3-ssid") +ssid = ns.wifi.Ssid("ns-3-ssid") wifi = ns.wifi.WifiHelper() -mac.SetType ("ns3::StaWifiMac", "Ssid", ns.wifi.SsidValue(ssid), "ActiveProbing", ns.core.BooleanValue(False)) +mac.SetType( + "ns3::StaWifiMac", "Ssid", ns.wifi.SsidValue(ssid), "ActiveProbing", ns.core.BooleanValue(False) +) staDevices = wifi.Install(phy, mac, wifiStaNodes) -mac.SetType("ns3::ApWifiMac","Ssid", ns.wifi.SsidValue (ssid)) +mac.SetType("ns3::ApWifiMac", "Ssid", ns.wifi.SsidValue(ssid)) apDevices = wifi.Install(phy, mac, wifiApNode) mobility = ns.mobility.MobilityHelper() -mobility.SetPositionAllocator("ns3::GridPositionAllocator", "MinX", ns.core.DoubleValue(0.0), - "MinY", ns.core.DoubleValue (0.0), "DeltaX", ns.core.DoubleValue(5.0), "DeltaY", ns.core.DoubleValue(10.0), - "GridWidth", ns.core.UintegerValue(3), "LayoutType", ns.core.StringValue("RowFirst")) +mobility.SetPositionAllocator( + "ns3::GridPositionAllocator", + "MinX", + ns.core.DoubleValue(0.0), + "MinY", + ns.core.DoubleValue(0.0), + "DeltaX", + ns.core.DoubleValue(5.0), + "DeltaY", + ns.core.DoubleValue(10.0), + "GridWidth", + ns.core.UintegerValue(3), + "LayoutType", + ns.core.StringValue("RowFirst"), +) -mobility.SetMobilityModel ("ns3::RandomWalk2dMobilityModel", "Bounds", ns.mobility.RectangleValue(ns.mobility.Rectangle (-50, 50, -50, 50))) +mobility.SetMobilityModel( + "ns3::RandomWalk2dMobilityModel", + "Bounds", + ns.mobility.RectangleValue(ns.mobility.Rectangle(-50, 50, -50, 50)), +) mobility.Install(wifiStaNodes) mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel") @@ -126,12 +151,14 @@ serverApps = echoServer.Install(csmaNodes.Get(nCsma.value)) serverApps.Start(ns.core.Seconds(1.0)) serverApps.Stop(ns.core.Seconds(10.0)) -echoClient = ns.applications.UdpEchoClientHelper(csmaInterfaces.GetAddress(nCsma.value).ConvertTo(), 9) +echoClient = ns.applications.UdpEchoClientHelper( + csmaInterfaces.GetAddress(nCsma.value).ConvertTo(), 9 +) echoClient.SetAttribute("MaxPackets", ns.core.UintegerValue(1)) -echoClient.SetAttribute("Interval", ns.core.TimeValue(ns.core.Seconds (1.0))) +echoClient.SetAttribute("Interval", ns.core.TimeValue(ns.core.Seconds(1.0))) echoClient.SetAttribute("PacketSize", ns.core.UintegerValue(1024)) -clientApps = echoClient.Install(wifiStaNodes.Get (nWifi.value - 1)) +clientApps = echoClient.Install(wifiStaNodes.Get(nWifi.value - 1)) clientApps.Start(ns.core.Seconds(2.0)) clientApps.Stop(ns.core.Seconds(10.0)) @@ -141,10 +168,9 @@ ns.core.Simulator.Stop(ns.core.Seconds(10.0)) if tracing.value: phy.SetPcapDataLinkType(phy.DLT_IEEE802_11_RADIO) - pointToPoint.EnablePcapAll ("third") - phy.EnablePcap ("third", apDevices.Get (0)) - csma.EnablePcap ("third", csmaDevices.Get (0), True) + pointToPoint.EnablePcapAll("third") + phy.EnablePcap("third", apDevices.Get(0)) + csma.EnablePcap("third", csmaDevices.Get(0), True) ns.core.Simulator.Run() ns.core.Simulator.Destroy() - diff --git a/examples/wireless/examples-to-run.py b/examples/wireless/examples-to-run.py index 3acd036ee..dc9b766cc 100755 --- a/examples/wireless/examples-to-run.py +++ b/examples/wireless/examples-to-run.py @@ -15,9 +15,9 @@ cpp_examples = [ ("wifi-multirate --totalTime=0.3s --rateManager=ns3::MinstrelWifiManager", "True", "False"), ("wifi-multirate --totalTime=0.3s --rateManager=ns3::OnoeWifiManager", "True", "False"), ("wifi-multirate --totalTime=0.3s --rateManager=ns3::RraaWifiManager", "True", "False"), - ("wifi-adhoc", "False", "True"), # Takes too long to run - ("wifi-ap --verbose=0", "True", "True"), # Don't let it spew to stdout - ("wifi-clear-channel-cmu", "False", "True"), # Requires specific hardware + ("wifi-adhoc", "False", "True"), # Takes too long to run + ("wifi-ap --verbose=0", "True", "True"), # Don't let it spew to stdout + ("wifi-clear-channel-cmu", "False", "True"), # Requires specific hardware ("wifi-simple-adhoc", "True", "True"), ("wifi-simple-adhoc-grid", "True", "True"), ("wifi-simple-infra", "True", "True"), @@ -26,12 +26,36 @@ cpp_examples = [ ("wifi-sleep", "True", "True"), ("wifi-blockack", "True", "True"), ("wifi-timing-attributes --simulationTime=1", "True", "True"), - ("wifi-power-adaptation-distance --manager=ns3::ParfWifiManager --outputFileName=parf --steps=5 --stepsSize=10", "True", "True"), - ("wifi-power-adaptation-distance --manager=ns3::AparfWifiManager --outputFileName=aparf --steps=5 --stepsSize=10", "True", "False"), - ("wifi-power-adaptation-distance --manager=ns3::RrpaaWifiManager --outputFileName=rrpaa --steps=5 --stepsSize=10", "True", "False"), - ("wifi-rate-adaptation-distance --standard=802.11a --staManager=ns3::MinstrelWifiManager --apManager=ns3::MinstrelWifiManager --outputFileName=minstrel --stepsSize=50 --stepsTime=0.1", "True", "False"), - ("wifi-rate-adaptation-distance --standard=802.11a --staManager=ns3::MinstrelWifiManager --apManager=ns3::MinstrelWifiManager --outputFileName=minstrel --stepsSize=50 --stepsTime=0.1 --STA1_x=-200", "True", "False"), - ("wifi-rate-adaptation-distance --staManager=ns3::MinstrelHtWifiManager --apManager=ns3::MinstrelHtWifiManager --outputFileName=minstrelHt --shortGuardInterval=true --channelWidth=40 --stepsSize=50 --stepsTime=0.1", "True", "False"), + ( + "wifi-power-adaptation-distance --manager=ns3::ParfWifiManager --outputFileName=parf --steps=5 --stepsSize=10", + "True", + "True", + ), + ( + "wifi-power-adaptation-distance --manager=ns3::AparfWifiManager --outputFileName=aparf --steps=5 --stepsSize=10", + "True", + "False", + ), + ( + "wifi-power-adaptation-distance --manager=ns3::RrpaaWifiManager --outputFileName=rrpaa --steps=5 --stepsSize=10", + "True", + "False", + ), + ( + "wifi-rate-adaptation-distance --standard=802.11a --staManager=ns3::MinstrelWifiManager --apManager=ns3::MinstrelWifiManager --outputFileName=minstrel --stepsSize=50 --stepsTime=0.1", + "True", + "False", + ), + ( + "wifi-rate-adaptation-distance --standard=802.11a --staManager=ns3::MinstrelWifiManager --apManager=ns3::MinstrelWifiManager --outputFileName=minstrel --stepsSize=50 --stepsTime=0.1 --STA1_x=-200", + "True", + "False", + ), + ( + "wifi-rate-adaptation-distance --staManager=ns3::MinstrelHtWifiManager --apManager=ns3::MinstrelHtWifiManager --outputFileName=minstrelHt --shortGuardInterval=true --channelWidth=40 --stepsSize=50 --stepsTime=0.1", + "True", + "False", + ), ("wifi-power-adaptation-interference --simuTime=5", "True", "False"), ("wifi-dsss-validation", "True", "True"), ("wifi-ofdm-validation", "True", "True"), @@ -40,37 +64,145 @@ cpp_examples = [ ("wifi-ofdm-he-validation", "True", "True"), ("wifi-error-models-comparison", "True", "True"), ("wifi-80211n-mimo --simulationTime=0.1 --step=10", "True", "True"), - ("wifi-ht-network --simulationTime=0.2 --frequency=5 --useRts=0 --minExpectedThroughput=5 --maxExpectedThroughput=135", "True", "True"), - ("wifi-ht-network --simulationTime=0.2 --frequency=5 --useRts=1 --minExpectedThroughput=5 --maxExpectedThroughput=132", "True", "True"), - ("wifi-ht-network --simulationTime=0.2 --frequency=2.4 --useRts=0 --minExpectedThroughput=5 --maxExpectedThroughput=132", "True", "True"), - ("wifi-ht-network --simulationTime=0.2 --frequency=2.4 --useRts=1 --minExpectedThroughput=5 --maxExpectedThroughput=129", "True", "True"), - ("wifi-vht-network --simulationTime=0.2 --useRts=0 --minExpectedThroughput=5 --maxExpectedThroughput=583", "True", "True"), - ("wifi-vht-network --simulationTime=0.2 --useRts=1 --minExpectedThroughput=5 --maxExpectedThroughput=557", "True", "True"), - ("wifi-he-network --simulationTime=0.25 --frequency=5 --useRts=0 --minExpectedThroughput=6 --maxExpectedThroughput=844", "True", "True"), - ("wifi-he-network --simulationTime=0.3 --frequency=5 --useRts=0 --useExtendedBlockAck=1 --minExpectedThroughput=6 --maxExpectedThroughput=1033", "True", "True"), - ("wifi-he-network --simulationTime=0.3 --frequency=5 --useRts=1 --minExpectedThroughput=6 --maxExpectedThroughput=745", "True", "True"), - ("wifi-he-network --simulationTime=0.25 --frequency=2.4 --useRts=0 --minExpectedThroughput=6 --maxExpectedThroughput=238", "True", "True"), - ("wifi-he-network --simulationTime=0.3 --frequency=2.4 --useRts=1 --minExpectedThroughput=6 --maxExpectedThroughput=223", "True", "True"), - ("wifi-he-network --simulationTime=0.3 --udp=0 --downlink=1 --useRts=0 --nStations=4 --dlAckType=ACK-SU-FORMAT --enableUlOfdma=1 --enableBsrp=0 --mcs=4 --minExpectedThroughput=20 --maxExpectedThroughput=212", "True", "True"), - ("wifi-he-network --simulationTime=0.3 --frequency=2.4 --udp=0 --downlink=1 --useRts=1 --nStations=5 --dlAckType=MU-BAR --enableUlOfdma=1 --enableBsrp=1 --mcs=5 --minExpectedThroughput=27 --maxExpectedThroughput=50", "True", "True"), - ("wifi-he-network --simulationTime=0.3 --udp=0 --downlink=1 --useRts=0 --nStations=5 --dlAckType=AGGR-MU-BAR --enableUlOfdma=1 --enableBsrp=0 --mcs=6 --muSchedAccessReqInterval=50ms --minExpectedThroughput=31 --maxExpectedThroughput=290", "True", "True"), - ("wifi-he-network --simulationTime=0.3 --udp=1 --downlink=0 --useRts=1 --nStations=5 --dlAckType=AGGR-MU-BAR --enableUlOfdma=1 --enableBsrp=1 --mcs=5 --muSchedAccessReqInterval=50ms --minExpectedThroughput=46 --maxExpectedThroughput=327", "True", "True"), - ("wifi-eht-network --simulationTime=0.1 --frequency=5 --useRts=0 --minExpectedThroughput=6 --maxExpectedThroughput=550", "True", "True"), - ("wifi-eht-network --simulationTime=0.1 --frequency=5 --useRts=0 --useExtendedBlockAck=1 --frequency2=6 --minExpectedThroughput=12 --maxExpectedThroughput=550", "True", "True"), - ("wifi-eht-network --simulationTime=0.1 --frequency=5 --useRts=1 --minExpectedThroughput=6 --maxExpectedThroughput=547", "True", "True"), - ("wifi-eht-network --simulationTime=0.1 --frequency=2.4 --useRts=0 --useExtendedBlockAck=1 --frequency2=5 --minExpectedThroughput=12 --maxExpectedThroughput=500", "True", "True"), - ("wifi-eht-network --simulationTime=0.1 --frequency=2.4 --useRts=1 --minExpectedThroughput=6 --maxExpectedThroughput=212", "True", "True"), - ("wifi-eht-network --simulationTime=0.23 --udp=0 --downlink=1 --useRts=0 --nStations=4 --dlAckType=ACK-SU-FORMAT --enableUlOfdma=1 --enableBsrp=0 --mcs=4 --frequency2=6 --minExpectedThroughput=35 --maxExpectedThroughput=280", "True", "True"), - ("wifi-eht-network --simulationTime=0.25 --frequency=2.4 --udp=0 --downlink=1 --useRts=0 --nStations=5 --dlAckType=MU-BAR --enableUlOfdma=1 --enableBsrp=1 --mcs=5 --frequency2=5 --useExtendedBlockAck=1 --minExpectedThroughput=40 --maxExpectedThroughput=100", "True", "True"), - ("wifi-eht-network --simulationTime=0.3 --udp=0 --downlink=1 --useRts=1 --nStations=5 --dlAckType=AGGR-MU-BAR --enableUlOfdma=1 --enableBsrp=0 --mcs=6 --muSchedAccessReqInterval=50ms --frequency2=2.4 --minExpectedThroughput=50 --maxExpectedThroughput=140", "True", "True"), - ("wifi-eht-network --simulationTime=0.2 --udp=1 --downlink=0 --useRts=0 --nStations=5 --dlAckType=AGGR-MU-BAR --enableUlOfdma=1 --enableBsrp=1 --mcs=5 --muSchedAccessReqInterval=50ms --frequency2=6 --minExpectedThroughput=70 --maxExpectedThroughput=715", "True", "True"), - ("wifi-simple-ht-hidden-stations --simulationTime=1 --enableRts=0 --nMpdus=32 --minExpectedThroughput=59 --maxExpectedThroughput=60", "True", "True"), - ("wifi-simple-ht-hidden-stations --simulationTime=1 --enableRts=1 --nMpdus=32 --minExpectedThroughput=57 --maxExpectedThroughput=58", "True", "True"), + ( + "wifi-ht-network --simulationTime=0.2 --frequency=5 --useRts=0 --minExpectedThroughput=5 --maxExpectedThroughput=135", + "True", + "True", + ), + ( + "wifi-ht-network --simulationTime=0.2 --frequency=5 --useRts=1 --minExpectedThroughput=5 --maxExpectedThroughput=132", + "True", + "True", + ), + ( + "wifi-ht-network --simulationTime=0.2 --frequency=2.4 --useRts=0 --minExpectedThroughput=5 --maxExpectedThroughput=132", + "True", + "True", + ), + ( + "wifi-ht-network --simulationTime=0.2 --frequency=2.4 --useRts=1 --minExpectedThroughput=5 --maxExpectedThroughput=129", + "True", + "True", + ), + ( + "wifi-vht-network --simulationTime=0.2 --useRts=0 --minExpectedThroughput=5 --maxExpectedThroughput=583", + "True", + "True", + ), + ( + "wifi-vht-network --simulationTime=0.2 --useRts=1 --minExpectedThroughput=5 --maxExpectedThroughput=557", + "True", + "True", + ), + ( + "wifi-he-network --simulationTime=0.25 --frequency=5 --useRts=0 --minExpectedThroughput=6 --maxExpectedThroughput=844", + "True", + "True", + ), + ( + "wifi-he-network --simulationTime=0.3 --frequency=5 --useRts=0 --useExtendedBlockAck=1 --minExpectedThroughput=6 --maxExpectedThroughput=1033", + "True", + "True", + ), + ( + "wifi-he-network --simulationTime=0.3 --frequency=5 --useRts=1 --minExpectedThroughput=6 --maxExpectedThroughput=745", + "True", + "True", + ), + ( + "wifi-he-network --simulationTime=0.25 --frequency=2.4 --useRts=0 --minExpectedThroughput=6 --maxExpectedThroughput=238", + "True", + "True", + ), + ( + "wifi-he-network --simulationTime=0.3 --frequency=2.4 --useRts=1 --minExpectedThroughput=6 --maxExpectedThroughput=223", + "True", + "True", + ), + ( + "wifi-he-network --simulationTime=0.3 --udp=0 --downlink=1 --useRts=0 --nStations=4 --dlAckType=ACK-SU-FORMAT --enableUlOfdma=1 --enableBsrp=0 --mcs=4 --minExpectedThroughput=20 --maxExpectedThroughput=212", + "True", + "True", + ), + ( + "wifi-he-network --simulationTime=0.3 --frequency=2.4 --udp=0 --downlink=1 --useRts=1 --nStations=5 --dlAckType=MU-BAR --enableUlOfdma=1 --enableBsrp=1 --mcs=5 --minExpectedThroughput=27 --maxExpectedThroughput=50", + "True", + "True", + ), + ( + "wifi-he-network --simulationTime=0.3 --udp=0 --downlink=1 --useRts=0 --nStations=5 --dlAckType=AGGR-MU-BAR --enableUlOfdma=1 --enableBsrp=0 --mcs=6 --muSchedAccessReqInterval=50ms --minExpectedThroughput=31 --maxExpectedThroughput=290", + "True", + "True", + ), + ( + "wifi-he-network --simulationTime=0.3 --udp=1 --downlink=0 --useRts=1 --nStations=5 --dlAckType=AGGR-MU-BAR --enableUlOfdma=1 --enableBsrp=1 --mcs=5 --muSchedAccessReqInterval=50ms --minExpectedThroughput=46 --maxExpectedThroughput=327", + "True", + "True", + ), + ( + "wifi-eht-network --simulationTime=0.1 --frequency=5 --useRts=0 --minExpectedThroughput=6 --maxExpectedThroughput=550", + "True", + "True", + ), + ( + "wifi-eht-network --simulationTime=0.1 --frequency=5 --useRts=0 --mpduBufferSize=1024 --frequency2=6 --minExpectedThroughput=12 --maxExpectedThroughput=550", + "True", + "True", + ), + ( + "wifi-eht-network --simulationTime=0.1 --frequency=5 --useRts=1 --minExpectedThroughput=6 --maxExpectedThroughput=547", + "True", + "True", + ), + ( + "wifi-eht-network --simulationTime=0.1 --frequency=2.4 --useRts=0 --mpduBufferSize=512 --frequency2=5 --minExpectedThroughput=12 --maxExpectedThroughput=500", + "True", + "True", + ), + ( + "wifi-eht-network --simulationTime=0.1 --frequency=2.4 --useRts=1 --minExpectedThroughput=5 --maxExpectedThroughput=240", + "True", + "True", + ), + ( + "wifi-eht-network --simulationTime=0.23 --udp=0 --downlink=1 --useRts=0 --nStations=4 --dlAckType=ACK-SU-FORMAT --enableUlOfdma=1 --enableBsrp=0 --mcs=5 --frequency2=6 --minExpectedThroughput=35 --maxExpectedThroughput=280", + "True", + "True", + ), + ( + "wifi-eht-network --simulationTime=0.25 --frequency=2.4 --udp=0 --downlink=1 --useRts=0 --nStations=5 --dlAckType=MU-BAR --enableUlOfdma=1 --enableBsrp=1 --mcs=5 --frequency2=5 --mpduBufferSize=1024 --minExpectedThroughput=50 --maxExpectedThroughput=120", + "True", + "True", + ), + ( + "wifi-eht-network --simulationTime=0.3 --udp=0 --downlink=1 --useRts=1 --nStations=5 --dlAckType=AGGR-MU-BAR --enableUlOfdma=1 --enableBsrp=0 --mcs=6 --muSchedAccessReqInterval=50ms --frequency2=2.4 --minExpectedThroughput=50 --maxExpectedThroughput=140", + "True", + "True", + ), + ( + "wifi-eht-network --simulationTime=0.2 --udp=0 --downlink=0 --useRts=0 --nStations=4 --dlAckType=AGGR-MU-BAR --enableUlOfdma=1 --enableBsrp=1 --mpduBufferSize=1024 --mcs=4 --muSchedAccessReqInterval=45ms --frequency2=6 --minExpectedThroughput=50 --maxExpectedThroughput=415", + "True", + "True", + ), + ( + "wifi-simple-ht-hidden-stations --simulationTime=1 --enableRts=0 --nMpdus=32 --minExpectedThroughput=59 --maxExpectedThroughput=60", + "True", + "True", + ), + ( + "wifi-simple-ht-hidden-stations --simulationTime=1 --enableRts=1 --nMpdus=32 --minExpectedThroughput=57 --maxExpectedThroughput=58", + "True", + "True", + ), ("wifi-mixed-network --simulationTime=1", "True", "True"), ("wifi-aggregation --simulationTime=1 --verifyResults=1", "True", "True"), ("wifi-txop-aggregation --simulationTime=1 --verifyResults=1", "True", "True"), ("wifi-80211e-txop --simulationTime=1 --verifyResults=1", "True", "True"), - ("wifi-multi-tos --simulationTime=1 --nWifi=16 --useRts=1 --useShortGuardInterval=1", "True", "True"), + ( + "wifi-multi-tos --simulationTime=1 --nWifi=16 --useRts=1 --useShortGuardInterval=1", + "True", + "True", + ), ("wifi-tcp", "True", "True"), ("wifi-hidden-terminal --wifiManager=Arf", "True", "True"), ("wifi-hidden-terminal --wifiManager=Aarf", "True", "True"), @@ -81,14 +213,42 @@ cpp_examples = [ ("wifi-hidden-terminal --wifiManager=Cara", "True", "True"), ("wifi-hidden-terminal --wifiManager=Rraa", "True", "True"), ("wifi-hidden-terminal --wifiManager=Rrpaa", "True", "True"), - ("wifi-spectrum-per-example --distance=52 --index=3 --wifiType=ns3::SpectrumWifiPhy --simulationTime=1", "True", "True"), - ("wifi-spectrum-per-example --distance=24 --index=31 --wifiType=ns3::YansWifiPhy --simulationTime=1", "True", "False"), - ("wifi-spectrum-per-interference --distance=24 --index=31 --simulationTime=1 --waveformPower=0.1", "True", "True"), + ( + "wifi-spectrum-per-example --distance=52 --index=3 --wifiType=ns3::SpectrumWifiPhy --simulationTime=1", + "True", + "True", + ), + ( + "wifi-spectrum-per-example --distance=24 --index=31 --wifiType=ns3::YansWifiPhy --simulationTime=1", + "True", + "False", + ), + ( + "wifi-spectrum-per-interference --distance=24 --index=31 --simulationTime=1 --waveformPower=0.1", + "True", + "True", + ), ("wifi-spectrum-saturation-example --simulationTime=1 --index=63", "True", "True"), - ("wifi-backward-compatibility --apVersion=80211a --staVersion=80211n_5GHZ --simulationTime=1", "True", "True"), - ("wifi-backward-compatibility --apVersion=80211a --staVersion=80211n_5GHZ --apRaa=Ideal --staRaa=Ideal --simulationTime=1", "True", "False"), - ("wifi-backward-compatibility --apVersion=80211a --staVersion=80211ac --simulationTime=1", "True", "False"), - ("wifi-backward-compatibility --apVersion=80211a --staVersion=80211ac --apRaa=Ideal --staRaa=Ideal --simulationTime=1", "True", "False"), + ( + "wifi-backward-compatibility --apVersion=80211a --staVersion=80211n_5GHZ --simulationTime=1", + "True", + "True", + ), + ( + "wifi-backward-compatibility --apVersion=80211a --staVersion=80211n_5GHZ --apRaa=Ideal --staRaa=Ideal --simulationTime=1", + "True", + "False", + ), + ( + "wifi-backward-compatibility --apVersion=80211a --staVersion=80211ac --simulationTime=1", + "True", + "False", + ), + ( + "wifi-backward-compatibility --apVersion=80211a --staVersion=80211ac --apRaa=Ideal --staRaa=Ideal --simulationTime=1", + "True", + "False", + ), ] # A list of Python examples to run in order to ensure that they remain diff --git a/examples/wireless/mixed-wired-wireless.py b/examples/wireless/mixed-wired-wireless.py index db595f52c..d34f099c4 100644 --- a/examples/wireless/mixed-wired-wireless.py +++ b/examples/wireless/mixed-wired-wireless.py @@ -51,7 +51,14 @@ # +----------------+ +----------------+ # -from ns import ns +try: + from ns import ns +except ModuleNotFoundError: + raise SystemExit( + "Error: ns3 Python module not found;" + " Python bindings may not be enabled" + " or your PYTHONPATH might not be properly configured" + ) # # # # This function will be used below as a trace sink @@ -63,12 +70,14 @@ from ns import ns # std.cout << "CourseChange " << path << " x=" << position.x << ", y=" << position.y << ", z=" << position.z << std.endl; # } + def main(argv): # # First, we initialize a few local variables that control some # simulation parameters. # - from ctypes import c_int, c_double + from ctypes import c_double, c_int + backboneNodes = c_int(10) infraNodes = c_int(2) lanNodes = c_int(2) @@ -99,8 +108,8 @@ def main(argv): # cmd.Parse(argv) - if (stopTime.value < 10): - print ("Use a simulation stop time >= 10 seconds") + if stopTime.value < 10: + print("Use a simulation stop time >= 10 seconds") exit(1) # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # / # # @@ -121,8 +130,9 @@ def main(argv): wifi = ns.wifi.WifiHelper() mac = ns.wifi.WifiMacHelper() mac.SetType("ns3::AdhocWifiMac") - wifi.SetRemoteStationManager("ns3::ConstantRateWifiManager", - "DataMode", ns.core.StringValue("OfdmRate54Mbps")) + wifi.SetRemoteStationManager( + "ns3::ConstantRateWifiManager", "DataMode", ns.core.StringValue("OfdmRate54Mbps") + ) wifiPhy = ns.wifi.YansWifiPhyHelper() wifiPhy.SetPcapDataLinkType(wifiPhy.DLT_IEEE802_11_RADIO) wifiChannel = ns.wifi.YansWifiChannelHelper.Default() @@ -131,11 +141,12 @@ def main(argv): # # Add the IPv4 protocol stack to the nodes in our container # - print ("Enabling OLSR routing on all backbone nodes") + print("Enabling OLSR routing on all backbone nodes") internet = ns.internet.InternetStackHelper() olsr = ns.olsr.OlsrHelper() - internet.SetRoutingHelper(olsr); # has effect on the next Install () - internet.Install(backbone); + internet.SetRoutingHelper(olsr) + # has effect on the next Install () + internet.Install(backbone) # re-initialize for non-olsr routing. # internet.Reset() # @@ -151,17 +162,30 @@ def main(argv): # each of the nodes we just finished building. # mobility = ns.mobility.MobilityHelper() - mobility.SetPositionAllocator("ns3::GridPositionAllocator", - "MinX", ns.core.DoubleValue(20.0), - "MinY", ns.core.DoubleValue(20.0), - "DeltaX", ns.core.DoubleValue(20.0), - "DeltaY", ns.core.DoubleValue(20.0), - "GridWidth", ns.core.UintegerValue(5), - "LayoutType", ns.core.StringValue("RowFirst")) - mobility.SetMobilityModel("ns3::RandomDirection2dMobilityModel", - "Bounds", ns.mobility.RectangleValue(ns.mobility.Rectangle(-500, 500, -500, 500)), - "Speed", ns.core.StringValue ("ns3::ConstantRandomVariable[Constant=2]"), - "Pause", ns.core.StringValue ("ns3::ConstantRandomVariable[Constant=0.2]")) + mobility.SetPositionAllocator( + "ns3::GridPositionAllocator", + "MinX", + ns.core.DoubleValue(20.0), + "MinY", + ns.core.DoubleValue(20.0), + "DeltaX", + ns.core.DoubleValue(20.0), + "DeltaY", + ns.core.DoubleValue(20.0), + "GridWidth", + ns.core.UintegerValue(5), + "LayoutType", + ns.core.StringValue("RowFirst"), + ) + mobility.SetMobilityModel( + "ns3::RandomDirection2dMobilityModel", + "Bounds", + ns.mobility.RectangleValue(ns.mobility.Rectangle(-500, 500, -500, 500)), + "Speed", + ns.core.StringValue("ns3::ConstantRandomVariable[Constant=2]"), + "Pause", + ns.core.StringValue("ns3::ConstantRandomVariable[Constant=0.2]"), + ) mobility.Install(backbone) # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # / @@ -175,7 +199,7 @@ def main(argv): ipAddrs.SetBase(ns.network.Ipv4Address("172.16.0.0"), ns.network.Ipv4Mask("255.255.255.0")) for i in range(backboneNodes.value): - print ("Configuring local area network for backbone node ", i) + print("Configuring local area network for backbone node ", i) # # Create a container to manage the nodes of the LAN. We need # two containers here; one with all of the new nodes, and one @@ -214,12 +238,12 @@ def main(argv): mobilityLan = ns.mobility.MobilityHelper() positionAlloc = ns.mobility.ListPositionAllocator() for j in range(newLanNodes.GetN()): - positionAlloc.Add(ns.core.Vector(0.0, (j*10 + 10), 0.0)) + positionAlloc.Add(ns.core.Vector(0.0, (j * 10 + 10), 0.0)) mobilityLan.SetPositionAllocator(positionAlloc) mobilityLan.PushReferenceMobilityModel(backbone.Get(i)) mobilityLan.SetMobilityModel("ns3::ConstantPositionMobilityModel") - mobilityLan.Install(newLanNodes); + mobilityLan.Install(newLanNodes) # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # / # # @@ -232,7 +256,7 @@ def main(argv): ipAddrs.SetBase(ns.network.Ipv4Address("10.0.0.0"), ns.network.Ipv4Mask("255.255.255.0")) tempRef = [] # list of references to be held to prevent garbage collection for i in range(backboneNodes.value): - print ("Configuring wireless network for backbone node ", i) + print("Configuring wireless network for backbone node ", i) # # Create a container to manage the nodes of the LAN. We need # two containers here; one with all of the new nodes, and one @@ -245,18 +269,16 @@ def main(argv): # # Create another ad hoc network and devices # - ssid = ns.wifi.Ssid('wifi-infra' + str(i)) + ssid = ns.wifi.Ssid("wifi-infra" + str(i)) wifiInfra = ns.wifi.WifiHelper() wifiPhy.SetChannel(wifiChannel.Create()) - macInfra = ns.wifi.WifiMacHelper(); - macInfra.SetType("ns3::StaWifiMac", - "Ssid", ns.wifi.SsidValue(ssid)) + macInfra = ns.wifi.WifiMacHelper() + macInfra.SetType("ns3::StaWifiMac", "Ssid", ns.wifi.SsidValue(ssid)) # setup stas staDevices = wifiInfra.Install(wifiPhy, macInfra, stas) # setup ap. - macInfra.SetType("ns3::ApWifiMac", - "Ssid", ns.wifi.SsidValue(ssid)) + macInfra.SetType("ns3::ApWifiMac", "Ssid", ns.wifi.SsidValue(ssid)) apDevices = wifiInfra.Install(wifiPhy, macInfra, backbone.Get(i)) # Collect all of these new devices infraDevices = ns.network.NetDeviceContainer(apDevices, staDevices) @@ -291,10 +313,15 @@ def main(argv): mobility.PushReferenceMobilityModel(backbone.Get(i)) mobility.SetPositionAllocator(subnetAlloc) - mobility.SetMobilityModel("ns3::RandomDirection2dMobilityModel", - "Bounds", ns.mobility.RectangleValue(ns.mobility.Rectangle(-10, 10, -10, 10)), - "Speed", ns.core.StringValue ("ns3::ConstantRandomVariable[Constant=3]"), - "Pause", ns.core.StringValue ("ns3::ConstantRandomVariable[Constant=0.4]")) + mobility.SetMobilityModel( + "ns3::RandomDirection2dMobilityModel", + "Bounds", + ns.mobility.RectangleValue(ns.mobility.Rectangle(-10, 10, -10, 10)), + "Speed", + ns.core.StringValue("ns3::ConstantRandomVariable[Constant=3]"), + "Pause", + ns.core.StringValue("ns3::ConstantRandomVariable[Constant=0.4]"), + ) mobility.Install(stas) # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # / @@ -305,18 +332,25 @@ def main(argv): # Create the OnOff application to send UDP datagrams of size # 210 bytes at a rate of 448 Kb/s, between two nodes - print ("Create Applications.") - port = 9 # Discard port(RFC 863) + print("Create Applications.") + port = 9 # Discard port(RFC 863) appSource = ns.network.NodeList.GetNode(backboneNodes.value) - lastNodeIndex = backboneNodes.value + backboneNodes.value*(lanNodes.value - 1) + backboneNodes.value*(infraNodes.value - 1) - 1 + lastNodeIndex = ( + backboneNodes.value + + backboneNodes.value * (lanNodes.value - 1) + + backboneNodes.value * (infraNodes.value - 1) + - 1 + ) appSink = ns.network.NodeList.GetNode(lastNodeIndex) - ns.cppyy.cppdef(""" + ns.cppyy.cppdef( + """ Ipv4Address getIpv4AddressFromNode(Ptr node){ return node->GetObject()->GetAddress(1,0).GetLocal(); } - """) + """ + ) # Let's fetch the IP address of the last node, which is on Ipv4Interface 1 remoteAddr = ns.cppyy.gbl.getIpv4AddressFromNode(appSink) socketAddr = ns.network.InetSocketAddress(remoteAddr, port) @@ -326,8 +360,12 @@ def main(argv): apps.Stop(ns.core.Seconds(stopTime.value - 1)) # Create a packet sink to receive these packets - sink = ns.applications.PacketSinkHelper("ns3::UdpSocketFactory", - ns.network.InetSocketAddress(ns.network.InetSocketAddress(ns.network.Ipv4Address.GetAny(), port)).ConvertTo()) + sink = ns.applications.PacketSinkHelper( + "ns3::UdpSocketFactory", + ns.network.InetSocketAddress( + ns.network.InetSocketAddress(ns.network.Ipv4Address.GetAny(), port) + ).ConvertTo(), + ) sinkContainer = ns.network.NodeContainer(appSink) apps = sink.Install(sinkContainer) apps.Start(ns.core.Seconds(3)) @@ -338,16 +376,16 @@ def main(argv): # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # / - print ("Configure Tracing.") + print("Configure Tracing.") csma = ns.csma.CsmaHelper() # # Let's set up some ns-2-like ascii traces, using another helper class # - ascii = ns.network.AsciiTraceHelper(); - stream = ascii.CreateFileStream("mixed-wireless.tr"); - wifiPhy.EnableAsciiAll(stream); - csma.EnableAsciiAll(stream); - internet.EnableAsciiIpv4All(stream); + ascii = ns.network.AsciiTraceHelper() + stream = ascii.CreateFileStream("mixed-wireless.tr") + wifiPhy.EnableAsciiAll(stream) + csma.EnableAsciiAll(stream) + internet.EnableAsciiIpv4All(stream) # Csma captures in non-promiscuous mode csma.EnablePcapAll("mixed-wireless", False) @@ -355,11 +393,10 @@ def main(argv): wifiPhy.EnablePcap("mixed-wireless", backboneDevices) wifiPhy.EnablePcap("mixed-wireless", appSink.GetId(), 0) -# #ifdef ENABLE_FOR_TRACING_EXAMPLE -# Config.Connect("/NodeList/*/$MobilityModel/CourseChange", -# MakeCallback(&CourseChangeCallback)) -# #endif - + # #ifdef ENABLE_FOR_TRACING_EXAMPLE + # Config.Connect("/NodeList/*/$MobilityModel/CourseChange", + # MakeCallback(&CourseChangeCallback)) + # #endif # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # @@ -367,13 +404,13 @@ def main(argv): # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # - print ("Run Simulation.") + print("Run Simulation.") ns.core.Simulator.Stop(ns.core.Seconds(stopTime.value)) ns.core.Simulator.Run() ns.core.Simulator.Destroy() -if __name__ == '__main__': + +if __name__ == "__main__": import sys + main(sys.argv) - - diff --git a/examples/wireless/wifi-80211e-txop.cc b/examples/wireless/wifi-80211e-txop.cc index 1656068af..9ebbd7486 100644 --- a/examples/wireless/wifi-80211e-txop.cc +++ b/examples/wireless/wifi-80211e-txop.cc @@ -28,6 +28,7 @@ #include "ns3/ssid.h" #include "ns3/string.h" #include "ns3/udp-client-server-helper.h" +#include "ns3/udp-server.h" #include "ns3/wifi-mac.h" #include "ns3/wifi-net-device.h" #include "ns3/yans-wifi-channel.h" diff --git a/examples/wireless/wifi-80211n-mimo.cc b/examples/wireless/wifi-80211n-mimo.cc index 09170539e..b6e7f1ef3 100644 --- a/examples/wireless/wifi-80211n-mimo.cc +++ b/examples/wireless/wifi-80211n-mimo.cc @@ -51,6 +51,7 @@ #include "ns3/ssid.h" #include "ns3/string.h" #include "ns3/udp-client-server-helper.h" +#include "ns3/udp-server.h" #include "ns3/uinteger.h" #include "ns3/yans-wifi-channel.h" #include "ns3/yans-wifi-helper.h" diff --git a/examples/wireless/wifi-aggregation.cc b/examples/wireless/wifi-aggregation.cc index 3f33abd20..9189051ff 100644 --- a/examples/wireless/wifi-aggregation.cc +++ b/examples/wireless/wifi-aggregation.cc @@ -28,6 +28,7 @@ #include "ns3/ssid.h" #include "ns3/string.h" #include "ns3/udp-client-server-helper.h" +#include "ns3/udp-server.h" #include "ns3/uinteger.h" #include "ns3/wifi-mac.h" #include "ns3/wifi-net-device.h" diff --git a/examples/wireless/wifi-ap.py b/examples/wireless/wifi-ap.py index 65be16d4a..464d9dfe5 100644 --- a/examples/wireless/wifi-ap.py +++ b/examples/wireless/wifi-ap.py @@ -22,7 +22,14 @@ import sys -from ns import ns +try: + from ns import ns +except ModuleNotFoundError: + raise SystemExit( + "Error: ns3 Python module not found;" + " Python bindings may not be enabled" + " or your PYTHONPATH might not be properly configured" + ) # void # DevTxTrace (std::string context, Ptr p, Mac48Address address) @@ -70,7 +77,8 @@ from ns import ns # std::cout << " start="< node){ Ptr mob = node->GetObject(); @@ -80,7 +88,9 @@ ns.cppyy.cppdef(""" return; mob->SetPosition(pos); Simulator::Schedule(Seconds(1.0), AdvancePosition, node); - }""") + }""" +) + def main(argv): ns.core.CommandLine().Parse(argv) @@ -91,7 +101,7 @@ def main(argv): mobility = ns.mobility.MobilityHelper() stas = ns.network.NodeContainer() ap = ns.network.NodeContainer() - #NetDeviceContainer staDevs; + # NetDeviceContainer staDevs; packetSocket = ns.network.PacketSocketHelper() stas.Create(2) @@ -109,15 +119,16 @@ def main(argv): wifiMac = ns.wifi.WifiMacHelper() # setup stas. - wifiMac.SetType("ns3::StaWifiMac", - "ActiveProbing", - ns.core.BooleanValue(True), - "Ssid", - ns.wifi.SsidValue(ssid)) + wifiMac.SetType( + "ns3::StaWifiMac", + "ActiveProbing", + ns.core.BooleanValue(True), + "Ssid", + ns.wifi.SsidValue(ssid), + ) staDevs = wifi.Install(wifiPhy, wifiMac, stas) # setup ap. - wifiMac.SetType("ns3::ApWifiMac", - "Ssid", ns.wifi.SsidValue(ssid)) + wifiMac.SetType("ns3::ApWifiMac", "Ssid", ns.wifi.SsidValue(ssid)) wifi.Install(wifiPhy, wifiMac, ap) # mobility. @@ -132,7 +143,7 @@ def main(argv): socket.SetProtocol(1) onoff = ns.applications.OnOffHelper("ns3::PacketSocketFactory", socket.ConvertTo()) - onoff.SetConstantRate (ns.network.DataRate ("500kb/s")) + onoff.SetConstantRate(ns.network.DataRate("500kb/s")) apps = onoff.Install(ns.network.NodeContainer(stas.Get(0))) apps.Start(ns.core.Seconds(0.5)) @@ -140,13 +151,12 @@ def main(argv): ns.core.Simulator.Stop(ns.core.Seconds(44.0)) - # Config::Connect("/NodeList/*/DeviceList/*/Tx", MakeCallback(&DevTxTrace)); - # Config::Connect("/NodeList/*/DeviceList/*/Rx", MakeCallback(&DevRxTrace)); - # Config::Connect("/NodeList/*/DeviceList/*/Phy/RxOk", MakeCallback(&PhyRxOkTrace)); - # Config::Connect("/NodeList/*/DeviceList/*/Phy/RxError", MakeCallback(&PhyRxErrorTrace)); - # Config::Connect("/NodeList/*/DeviceList/*/Phy/Tx", MakeCallback(&PhyTxTrace)); - # Config::Connect("/NodeList/*/DeviceList/*/Phy/State", MakeCallback(&PhyStateTrace)); - + # Config::Connect("/NodeList/*/DeviceList/*/Tx", MakeCallback(&DevTxTrace)); + # Config::Connect("/NodeList/*/DeviceList/*/Rx", MakeCallback(&DevRxTrace)); + # Config::Connect("/NodeList/*/DeviceList/*/Phy/RxOk", MakeCallback(&PhyRxOkTrace)); + # Config::Connect("/NodeList/*/DeviceList/*/Phy/RxError", MakeCallback(&PhyRxErrorTrace)); + # Config::Connect("/NodeList/*/DeviceList/*/Phy/Tx", MakeCallback(&PhyTxTrace)); + # Config::Connect("/NodeList/*/DeviceList/*/Phy/State", MakeCallback(&PhyStateTrace)); ns.core.Simulator.Run() ns.core.Simulator.Destroy() @@ -154,6 +164,5 @@ def main(argv): return 0 -if __name__ == '__main__': +if __name__ == "__main__": sys.exit(main(sys.argv)) - diff --git a/examples/wireless/wifi-backward-compatibility.cc b/examples/wireless/wifi-backward-compatibility.cc index 510c10d3d..07db57e23 100644 --- a/examples/wireless/wifi-backward-compatibility.cc +++ b/examples/wireless/wifi-backward-compatibility.cc @@ -30,6 +30,7 @@ #include "ns3/ssid.h" #include "ns3/tuple.h" #include "ns3/udp-client-server-helper.h" +#include "ns3/udp-server.h" #include "ns3/uinteger.h" #include "ns3/yans-wifi-channel.h" #include "ns3/yans-wifi-helper.h" @@ -149,7 +150,7 @@ main(int argc, char* argv[]) WifiMacHelper mac; WifiHelper wifi; Ssid ssid = Ssid("ns3"); - TupleValue channelValue; + TupleValue, UintegerValue> channelValue; const auto& [staStandard, staBand] = ConvertStringToStandardAndBand(staVersion); wifi.SetStandard(staStandard); diff --git a/examples/wireless/wifi-eht-network.cc b/examples/wireless/wifi-eht-network.cc index 7036f3c43..a2b2b5e7d 100644 --- a/examples/wireless/wifi-eht-network.cc +++ b/examples/wireless/wifi-eht-network.cc @@ -25,7 +25,6 @@ #include "ns3/enum.h" #include "ns3/internet-stack-helper.h" #include "ns3/ipv4-address-helper.h" -#include "ns3/ipv4-global-routing-helper.h" #include "ns3/log.h" #include "ns3/mobility-helper.h" #include "ns3/multi-model-spectrum-channel.h" @@ -37,6 +36,7 @@ #include "ns3/ssid.h" #include "ns3/string.h" #include "ns3/udp-client-server-helper.h" +#include "ns3/udp-server.h" #include "ns3/uinteger.h" #include "ns3/wifi-acknowledgment.h" #include "ns3/yans-wifi-channel.h" @@ -93,7 +93,7 @@ GetRxBytes(bool udp, const ApplicationContainer& serverApp, uint32_t payloadSize } } return rxBytes; -}; +} /** * Print average throughput over an intermediate time interval. @@ -146,7 +146,12 @@ main(int argc, char* argv[]) bool udp{true}; bool downlink{true}; bool useRts{false}; - bool useExtendedBlockAck{false}; + uint16_t mpduBufferSize{512}; + std::string emlsrLinks; + uint16_t paddingDelayUsec{32}; + uint16_t transitionDelayUsec{128}; + uint16_t channelSwitchDelayUsec{100}; + bool switchAuxPhy{true}; double simulationTime{10}; // seconds double distance{1.0}; // meters double frequency{5}; // whether the first link operates in the 2.4, 5 or 6 GHz @@ -181,6 +186,22 @@ main(int argc, char* argv[]) "Whether the third link operates in the 2.4, 5 or 6 GHz band (0 means the device has up to " "two links, otherwise the band must be different than first link and second link)", frequency3); + cmd.AddValue("emlsrLinks", + "The comma separated list of IDs of EMLSR links (for MLDs only)", + emlsrLinks); + cmd.AddValue("emlsrPaddingDelay", + "The EMLSR padding delay in microseconds (0, 32, 64, 128 or 256)", + paddingDelayUsec); + cmd.AddValue("emlsrTransitionDelay", + "The EMLSR transition delay in microseconds (0, 16, 32, 64, 128 or 256)", + transitionDelayUsec); + cmd.AddValue("emlsrAuxSwitch", + "Whether Aux PHY should switch channel to operate on the link on which " + "the Main PHY was operating before moving to the link of the Aux PHY. ", + switchAuxPhy); + cmd.AddValue("channelSwitchDelay", + "The PHY channel switch delay in microseconds", + channelSwitchDelayUsec); cmd.AddValue("distance", "Distance in meters between the station and the access point", distance); @@ -190,7 +211,9 @@ main(int argc, char* argv[]) "Generate downlink flows if set to 1, uplink flows otherwise", downlink); cmd.AddValue("useRts", "Enable/disable RTS/CTS", useRts); - cmd.AddValue("useExtendedBlockAck", "Enable/disable use of extended BACK", useExtendedBlockAck); + cmd.AddValue("mpduBufferSize", + "Size (in number of MPDUs) of the BlockAck buffer", + mpduBufferSize); cmd.AddValue("nStations", "Number of non-AP HE stations", nStations); cmd.AddValue("dlAckType", "Ack sequence type for DL OFDMA (NO-OFDMA, ACK-SU-FORMAT, MU-BAR, AGGR-MU-BAR)", @@ -286,6 +309,7 @@ main(int argc, char* argv[]) wifi.SetStandard(WIFI_STANDARD_80211be); std::array channelStr; + std::array freqRanges; uint8_t nLinks = 0; std::string dataModeStr = "EhtMcs" + std::to_string(mcs); std::string ctrlRateStr; @@ -308,6 +332,7 @@ main(int argc, char* argv[]) if (freq == 6) { channelStr[nLinks] += "BAND_6GHZ, 0}"; + freqRanges[nLinks] = WIFI_SPECTRUM_6_GHZ; Config::SetDefault("ns3::LogDistancePropagationLossModel::ReferenceLoss", DoubleValue(48)); wifi.SetRemoteStationManager(nLinks, @@ -320,6 +345,7 @@ main(int argc, char* argv[]) else if (freq == 5) { channelStr[nLinks] += "BAND_5GHZ, 0}"; + freqRanges[nLinks] = WIFI_SPECTRUM_5_GHZ; ctrlRateStr = "OfdmRate" + std::to_string(nonHtRefRateMbps) + "Mbps"; wifi.SetRemoteStationManager(nLinks, "ns3::ConstantRateWifiManager", @@ -331,6 +357,7 @@ main(int argc, char* argv[]) else if (freq == 2.4) { channelStr[nLinks] += "BAND_2_4GHZ, 0}"; + freqRanges[nLinks] = WIFI_SPECTRUM_2_4_GHZ; Config::SetDefault("ns3::LogDistancePropagationLossModel::ReferenceLoss", DoubleValue(40)); ctrlRateStr = "ErpOfdmRate" + std::to_string(nonHtRefRateMbps) + "Mbps"; @@ -349,6 +376,11 @@ main(int argc, char* argv[]) nLinks++; } + if (nLinks > 1 && !emlsrLinks.empty()) + { + wifi.ConfigEhtOptions("EmlsrActivated", BooleanValue(true)); + } + Ssid ssid = Ssid("ns3-80211be"); /* @@ -357,21 +389,28 @@ main(int argc, char* argv[]) * and one with 312.5 kHz bands for, e.g., non-HT PPDUs (for more details, * see issue #408 (CLOSED)) */ - Ptr spectrumChannel = - CreateObject(); - - Ptr lossModel = - CreateObject(); - spectrumChannel->AddPropagationLossModel(lossModel); - SpectrumWifiPhyHelper phy(nLinks); phy.SetPcapDataLinkType(WifiPhyHelper::DLT_IEEE802_11_RADIO); - phy.SetChannel(spectrumChannel); + phy.Set("ChannelSwitchDelay", TimeValue(MicroSeconds(channelSwitchDelayUsec))); mac.SetType("ns3::StaWifiMac", "Ssid", SsidValue(ssid)); + mac.SetEmlsrManager("ns3::DefaultEmlsrManager", + "EmlsrLinkSet", + StringValue(emlsrLinks), + "EmlsrPaddingDelay", + TimeValue(MicroSeconds(paddingDelayUsec)), + "EmlsrTransitionDelay", + TimeValue(MicroSeconds(transitionDelayUsec)), + "SwitchAuxPhy", + BooleanValue(switchAuxPhy)); for (uint8_t linkId = 0; linkId < nLinks; linkId++) { phy.Set(linkId, "ChannelSettings", StringValue(channelStr[linkId])); + + auto spectrumChannel = CreateObject(); + auto lossModel = CreateObject(); + spectrumChannel->AddPropagationLossModel(lossModel); + phy.AddChannel(spectrumChannel, freqRanges[linkId]); } staDevices = wifi.Install(phy, mac, wifiStaNodes); @@ -402,9 +441,8 @@ main(int argc, char* argv[]) Config::Set( "/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/HeConfiguration/GuardInterval", TimeValue(NanoSeconds(gi))); - Config::Set( - "/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/HeConfiguration/MpduBufferSize", - UintegerValue(useExtendedBlockAck ? 256 : 64)); + Config::Set("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Mac/MpduBufferSize", + UintegerValue(mpduBufferSize)); // mobility. MobilityHelper mobility; @@ -507,8 +545,6 @@ main(int argc, char* argv[]) simulationTime + 1); } - Simulator::Schedule(Seconds(0), &Ipv4GlobalRoutingHelper::PopulateRoutingTables); - Simulator::Stop(Seconds(simulationTime + 1)); Simulator::Run(); diff --git a/examples/wireless/wifi-he-network.cc b/examples/wireless/wifi-he-network.cc index fe380dba4..a13a9d5d8 100644 --- a/examples/wireless/wifi-he-network.cc +++ b/examples/wireless/wifi-he-network.cc @@ -37,6 +37,7 @@ #include "ns3/ssid.h" #include "ns3/string.h" #include "ns3/udp-client-server-helper.h" +#include "ns3/udp-server.h" #include "ns3/uinteger.h" #include "ns3/wifi-acknowledgment.h" #include "ns3/yans-wifi-channel.h" @@ -250,11 +251,8 @@ main(int argc, char* argv[]) StringValue(ossDataMode.str()), "ControlMode", ctrlRate); - // Set guard interval and MPDU buffer size - wifi.ConfigHeOptions("GuardInterval", - TimeValue(NanoSeconds(gi)), - "MpduBufferSize", - UintegerValue(useExtendedBlockAck ? 256 : 64)); + // Set guard interval + wifi.ConfigHeOptions("GuardInterval", TimeValue(NanoSeconds(gi))); Ssid ssid = Ssid("ns3-80211ax"); @@ -277,7 +275,11 @@ main(int argc, char* argv[]) phy.SetPcapDataLinkType(WifiPhyHelper::DLT_IEEE802_11_RADIO); phy.SetChannel(spectrumChannel); - mac.SetType("ns3::StaWifiMac", "Ssid", SsidValue(ssid)); + mac.SetType("ns3::StaWifiMac", + "Ssid", + SsidValue(ssid), + "MpduBufferSize", + UintegerValue(useExtendedBlockAck ? 256 : 64)); phy.Set("ChannelSettings", StringValue(channelStr)); staDevices = wifi.Install(phy, mac, wifiStaNodes); @@ -305,7 +307,11 @@ main(int argc, char* argv[]) phy.SetPcapDataLinkType(WifiPhyHelper::DLT_IEEE802_11_RADIO); phy.SetChannel(channel.Create()); - mac.SetType("ns3::StaWifiMac", "Ssid", SsidValue(ssid)); + mac.SetType("ns3::StaWifiMac", + "Ssid", + SsidValue(ssid), + "MpduBufferSize", + UintegerValue(useExtendedBlockAck ? 256 : 64)); phy.Set("ChannelSettings", StringValue(channelStr)); staDevices = wifi.Install(phy, mac, wifiStaNodes); diff --git a/examples/wireless/wifi-ht-network.cc b/examples/wireless/wifi-ht-network.cc index d9fa8df55..64f135ddc 100644 --- a/examples/wireless/wifi-ht-network.cc +++ b/examples/wireless/wifi-ht-network.cc @@ -36,6 +36,7 @@ #include "ns3/string.h" #include "ns3/tuple.h" #include "ns3/udp-client-server-helper.h" +#include "ns3/udp-server.h" #include "ns3/uinteger.h" #include "ns3/yans-wifi-channel.h" #include "ns3/yans-wifi-helper.h" @@ -176,7 +177,8 @@ main(int argc, char* argv[]) wifi.ConfigHtOptions("ShortGuardIntervalSupported", BooleanValue(sgi)); Ssid ssid = Ssid("ns3-80211n"); - TupleValue channelValue; + TupleValue, UintegerValue> + channelValue; WifiPhyBand band = (frequency == 5.0 ? WIFI_PHY_BAND_5GHZ : WIFI_PHY_BAND_2_4GHZ); channelValue.Set(WifiPhy::ChannelTuple{0, channelWidth, band, 0}); diff --git a/examples/wireless/wifi-mixed-network.cc b/examples/wireless/wifi-mixed-network.cc index b079842f0..695a82452 100644 --- a/examples/wireless/wifi-mixed-network.cc +++ b/examples/wireless/wifi-mixed-network.cc @@ -32,6 +32,7 @@ #include "ns3/ssid.h" #include "ns3/string.h" #include "ns3/udp-client-server-helper.h" +#include "ns3/udp-server.h" #include "ns3/wifi-mac.h" #include "ns3/wifi-net-device.h" #include "ns3/yans-wifi-channel.h" diff --git a/examples/wireless/wifi-multi-tos.cc b/examples/wireless/wifi-multi-tos.cc index efdb9d879..17147bc63 100644 --- a/examples/wireless/wifi-multi-tos.cc +++ b/examples/wireless/wifi-multi-tos.cc @@ -191,7 +191,7 @@ main(int argc, char* argv[]) } else { - NS_LOG_ERROR("Obtained throughput is 0!"); + std::cout << "Obtained throughput is 0!" << std::endl; exit(1); } diff --git a/examples/wireless/wifi-power-adaptation-interference.cc b/examples/wireless/wifi-power-adaptation-interference.cc index e72ac666d..7932a1f0b 100644 --- a/examples/wireless/wifi-power-adaptation-interference.cc +++ b/examples/wireless/wifi-power-adaptation-interference.cc @@ -670,7 +670,7 @@ main(int argc, char* argv[]) for (auto i = stats.begin(); i != stats.end(); ++i) { Ipv4FlowClassifier::FiveTuple t = classifier->FindFlow(i->first); - if ((t.sourceAddress == "10.1.1.3" && t.destinationAddress == "10.1.1.1")) + if (t.sourceAddress == "10.1.1.3" && t.destinationAddress == "10.1.1.1") { NS_LOG_INFO("Flow " << i->first << " (" << t.sourceAddress << " -> " << t.destinationAddress << ")\n"); @@ -688,7 +688,7 @@ main(int argc, char* argv[]) << i->second.jitterSum.GetSeconds() / (i->second.rxPackets - 1) << "\n"); NS_LOG_INFO(" Tx Opp: " << 1 - (statisticsAp0.GetBusyTime() / simuTime)); } - if ((t.sourceAddress == "10.1.1.4" && t.destinationAddress == "10.1.1.2")) + if (t.sourceAddress == "10.1.1.4" && t.destinationAddress == "10.1.1.2") { NS_LOG_INFO("Flow " << i->first << " (" << t.sourceAddress << " -> " << t.destinationAddress << ")\n"); diff --git a/examples/wireless/wifi-simple-ht-hidden-stations.cc b/examples/wireless/wifi-simple-ht-hidden-stations.cc index 58f238080..7e177c463 100644 --- a/examples/wireless/wifi-simple-ht-hidden-stations.cc +++ b/examples/wireless/wifi-simple-ht-hidden-stations.cc @@ -25,9 +25,11 @@ #include "ns3/ipv4-address-helper.h" #include "ns3/log.h" #include "ns3/mobility-helper.h" +#include "ns3/rng-seed-manager.h" #include "ns3/ssid.h" #include "ns3/string.h" #include "ns3/udp-client-server-helper.h" +#include "ns3/udp-server.h" #include "ns3/uinteger.h" #include "ns3/yans-wifi-channel.h" #include "ns3/yans-wifi-helper.h" @@ -63,6 +65,9 @@ main(int argc, char* argv[]) double minExpectedThroughput = 0; double maxExpectedThroughput = 0; + RngSeedManager::SetSeed(1); + RngSeedManager::SetRun(5); + CommandLine cmd(__FILE__); cmd.AddValue("nMpdus", "Number of aggregated MPDUs", nMpdus); cmd.AddValue("payloadSize", "Payload size in bytes", payloadSize); diff --git a/examples/wireless/wifi-spatial-reuse.cc b/examples/wireless/wifi-spatial-reuse.cc index efcdcfa17..1b898f0bd 100644 --- a/examples/wireless/wifi-spatial-reuse.cc +++ b/examples/wireless/wifi-spatial-reuse.cc @@ -23,7 +23,7 @@ // // The geometry is as follows: // -// STA1 STA1 +// STA1 STA2 // | | // d1 | |d2 // | d3 | @@ -34,7 +34,7 @@ // // STA1 is continuously transmitting data to AP1, while STA2 is continuously sending data to AP2. // Each STA has configurable traffic loads (inter packet interval and packet size). -// It is also possible to configure TX power per node as well as their CCA-ED tresholds. +// It is also possible to configure TX power per node as well as their CCA-ED thresholds. // OBSS_PD spatial reuse feature can be enabled (default) or disabled, and the OBSS_PD // threshold can be set as well (default: -72 dBm). // A simple Friis path loss model is used and a constant PHY rate is considered. @@ -81,6 +81,9 @@ // benefits of spatial reuse in this scenario. This can, for // instance, be accomplished by setting --interval=0.0001. // +// Spatial reuse reset events are traced in two text files: +// - wifi-spatial-reuse-resets-bss-1.txt (for STA 1) +// - wifi-spatial-reuse-resets-bss-2.txt (for STA 2) #include "ns3/abort.h" #include "ns3/ap-wifi-mac.h" @@ -89,8 +92,10 @@ #include "ns3/config.h" #include "ns3/double.h" #include "ns3/he-configuration.h" +#include "ns3/he-phy.h" #include "ns3/mobility-helper.h" #include "ns3/multi-model-spectrum-channel.h" +#include "ns3/obss-pd-algorithm.h" #include "ns3/packet-socket-client.h" #include "ns3/packet-socket-helper.h" #include "ns3/packet-socket-server.h" @@ -102,6 +107,8 @@ using namespace ns3; std::vector bytesReceived(4); +std::ofstream g_resetFile1; +std::ofstream g_resetFile2; uint32_t ContextToNodeId(std::string context) @@ -118,6 +125,34 @@ SocketRx(std::string context, Ptr p, const Address& addr) bytesReceived[nodeId] += p->GetSize(); } +void +ResetTrace(std::string context, + uint8_t bssColor, + double rssiDbm, + bool powerRestricted, + double txPowerMaxDbmSiso, + double txPowerMaxDbmMimo) +{ + if (context == "1") + { + g_resetFile1 << Simulator::Now().GetSeconds() << " bssColor: " << +bssColor + << " rssiDbm: " << rssiDbm << " powerRestricted: " << powerRestricted + << " txPowerMaxDbmSiso: " << txPowerMaxDbmSiso + << " txPowerMaxDbmMimo: " << txPowerMaxDbmMimo << std::endl; + } + else if (context == "2") + { + g_resetFile2 << Simulator::Now().GetSeconds() << " bssColor: " << +bssColor + << " rssiDbm: " << rssiDbm << " powerRestricted: " << powerRestricted + << " txPowerMaxDbmSiso: " << txPowerMaxDbmSiso + << " txPowerMaxDbmMimo: " << txPowerMaxDbmMimo << std::endl; + } + else + { + NS_FATAL_ERROR("Unknown context " << context); + } +} + int main(int argc, char* argv[]) { @@ -164,6 +199,9 @@ main(int argc, char* argv[]) cmd.AddValue("mcs", "The constant MCS value to transmit HE PPDUs", mcs); cmd.Parse(argc, argv); + g_resetFile1.open("wifi-spatial-reuse-resets-bss-1.txt", std::ofstream::out); + g_resetFile2.open("wifi-spatial-reuse-resets-bss-2.txt", std::ofstream::out); + NodeContainer wifiStaNodes; wifiStaNodes.Create(2); @@ -318,6 +356,18 @@ main(int argc, char* argv[]) Config::Connect("/NodeList/*/ApplicationList/*/$ns3::PacketSocketServer/Rx", MakeCallback(&SocketRx)); + // Obtain pointers to the ObssPdAlgorithm objects and hook trace sinks + // to the Reset trace source on each STA. Note that this trace connection + // cannot be done through the Config path system, so pointers are used. + auto deviceA = staDeviceA.Get(0)->GetObject(); + auto hePhyA = DynamicCast(deviceA->GetPhy()->GetPhyEntity(WIFI_MOD_CLASS_HE)); + // Pass in the context string "1" to allow the trace to distinguish objects + hePhyA->GetObssPdAlgorithm()->TraceConnect("Reset", "1", MakeCallback(&ResetTrace)); + auto deviceB = staDeviceB.Get(0)->GetObject(); + auto hePhyB = DynamicCast(deviceB->GetPhy()->GetPhyEntity(WIFI_MOD_CLASS_HE)); + // Pass in the context string "2" to allow the trace to distinguish objects + hePhyB->GetObssPdAlgorithm()->TraceConnect("Reset", "2", MakeCallback(&ResetTrace)); + Simulator::Stop(Seconds(duration)); Simulator::Run(); @@ -329,5 +379,8 @@ main(int argc, char* argv[]) std::cout << "Throughput for BSS " << i + 1 << ": " << throughput << " Mbit/s" << std::endl; } + g_resetFile1.close(); + g_resetFile2.close(); + return 0; } diff --git a/examples/wireless/wifi-spectrum-per-example.cc b/examples/wireless/wifi-spectrum-per-example.cc index 15f8d1a29..931e66d4e 100644 --- a/examples/wireless/wifi-spectrum-per-example.cc +++ b/examples/wireless/wifi-spectrum-per-example.cc @@ -40,6 +40,7 @@ #include "ns3/ssid.h" #include "ns3/string.h" #include "ns3/udp-client-server-helper.h" +#include "ns3/udp-server.h" #include "ns3/uinteger.h" #include "ns3/yans-wifi-channel.h" #include "ns3/yans-wifi-helper.h" diff --git a/examples/wireless/wifi-spectrum-per-interference.cc b/examples/wireless/wifi-spectrum-per-interference.cc index 61f21dc67..4cc273cfd 100644 --- a/examples/wireless/wifi-spectrum-per-interference.cc +++ b/examples/wireless/wifi-spectrum-per-interference.cc @@ -37,6 +37,7 @@ #include "ns3/ssid.h" #include "ns3/string.h" #include "ns3/udp-client-server-helper.h" +#include "ns3/udp-server.h" #include "ns3/waveform-generator-helper.h" #include "ns3/waveform-generator.h" #include "ns3/wifi-net-device.h" diff --git a/examples/wireless/wifi-spectrum-saturation-example.cc b/examples/wireless/wifi-spectrum-saturation-example.cc index 306d16ce5..c329c8c09 100644 --- a/examples/wireless/wifi-spectrum-saturation-example.cc +++ b/examples/wireless/wifi-spectrum-saturation-example.cc @@ -36,6 +36,7 @@ #include "ns3/ssid.h" #include "ns3/string.h" #include "ns3/udp-client-server-helper.h" +#include "ns3/udp-server.h" #include "ns3/uinteger.h" #include "ns3/yans-wifi-channel.h" #include "ns3/yans-wifi-helper.h" diff --git a/examples/wireless/wifi-timing-attributes.cc b/examples/wireless/wifi-timing-attributes.cc index 48d135054..bd55cbe7d 100644 --- a/examples/wireless/wifi-timing-attributes.cc +++ b/examples/wireless/wifi-timing-attributes.cc @@ -29,6 +29,7 @@ #include "ns3/ssid.h" #include "ns3/string.h" #include "ns3/udp-client-server-helper.h" +#include "ns3/udp-server.h" #include "ns3/uinteger.h" #include "ns3/yans-wifi-channel.h" #include "ns3/yans-wifi-helper.h" diff --git a/examples/wireless/wifi-txop-aggregation.cc b/examples/wireless/wifi-txop-aggregation.cc index 385d1630a..beb15628b 100644 --- a/examples/wireless/wifi-txop-aggregation.cc +++ b/examples/wireless/wifi-txop-aggregation.cc @@ -30,6 +30,7 @@ #include "ns3/ssid.h" #include "ns3/string.h" #include "ns3/udp-client-server-helper.h" +#include "ns3/udp-server.h" #include "ns3/uinteger.h" #include "ns3/wifi-mac.h" #include "ns3/wifi-net-device.h" diff --git a/examples/wireless/wifi-vht-network.cc b/examples/wireless/wifi-vht-network.cc index f8c679a49..34837f73b 100644 --- a/examples/wireless/wifi-vht-network.cc +++ b/examples/wireless/wifi-vht-network.cc @@ -32,6 +32,7 @@ #include "ns3/ssid.h" #include "ns3/string.h" #include "ns3/udp-client-server-helper.h" +#include "ns3/udp-server.h" #include "ns3/uinteger.h" #include "ns3/vht-phy.h" #include "ns3/yans-wifi-channel.h" diff --git a/ns3 b/ns3 index 4745aded2..e33245709 100755 --- a/ns3 +++ b/ns3 @@ -2,6 +2,7 @@ import argparse import atexit +import functools import glob import os import re @@ -10,6 +11,7 @@ import subprocess import sys ns3_path = os.path.dirname(os.path.abspath(__file__)) +append_to_ns3_path = functools.partial(os.path.join, ns3_path) out_dir = os.sep.join([ns3_path, "build"]) lock_file = os.sep.join([ns3_path, ".lock-ns3_%s_build" % sys.platform]) @@ -30,7 +32,7 @@ def exit_handler(dry_run): return if print_buffer == "": return - print_buffer = print_buffer.replace('\\', '/').replace('//', '/').replace('/', os.sep) + print_buffer = print_buffer.replace("\\", "/").replace("//", "/").replace("/", os.sep) if dry_run: print("The following commands would be executed:") elif run_verbose: @@ -39,12 +41,18 @@ def exit_handler(dry_run): def on_off_argument(parser, option_name, help_on, help_off=None): - parser.add_argument('--enable-%s' % option_name, - help=('Enable %s' % help_on) if help_off is None else help_on, - action="store_true", default=None) - parser.add_argument('--disable-%s' % option_name, - help=('Disable %s' % help_on) if help_off is None else help_off, - action="store_true", default=None) + parser.add_argument( + "--enable-%s" % option_name, + help=("Enable %s" % help_on) if help_off is None else help_on, + action="store_true", + default=None, + ) + parser.add_argument( + "--disable-%s" % option_name, + help=("Disable %s" % help_on) if help_off is None else help_off, + action="store_true", + default=None, + ) return parser @@ -61,36 +69,42 @@ def on_off_condition(args, cmake_flag, option_name): return cmake_arg -def add_argument_to_subparsers(parsers: list, - arguments: list, - help_msg: str, - dest: str, - action="store_true", - default_value=None): +def add_argument_to_subparsers( + parsers: list, + arguments: list, + help_msg: str, + dest: str, + action="store_true", + default_value=None, +): # Instead of copying and pasting repeated arguments for each parser, we add them here for subparser in parsers: subparser_name = subparser.prog.replace("ns3", "").strip() destination = ("%s_%s" % (subparser_name, dest)) if subparser_name else dest - subparser.add_argument(*arguments, - help=help_msg, - action=action, - default=default_value, - dest=destination) + subparser.add_argument( + *arguments, help=help_msg, action=action, default=default_value, dest=destination + ) def parse_args(argv): - parser = argparse.ArgumentParser(description="ns-3 wrapper for the CMake build system", add_help=False) + parser = argparse.ArgumentParser( + description="ns-3 wrapper for the CMake build system", add_help=False + ) sub_parser = parser.add_subparsers() - parser.add_argument('-h', '--help', - help="Print a summary of available commands", - action="store_true", default=None, dest="main_help") - parser_help = sub_parser.add_parser('help', - help='Print a summary of available commands') - parser_help.add_argument('help', - help='Print a summary of available commands', - action="store_true", default=False) + parser.add_argument( + "-h", + "--help", + help="Print a summary of available commands", + action="store_true", + default=None, + dest="main_help", + ) + parser_help = sub_parser.add_parser("help", help="Print a summary of available commands") + parser_help.add_argument( + "help", help="Print a summary of available commands", action="store_true", default=False + ) # parser.add_argument('--docset', # help=( # 'Create Docset, without building. This requires the docsetutil tool from Xcode 9.2 or earlier.' @@ -98,34 +112,56 @@ def parse_args(argv): # action="store_true", default=None, # dest="docset_build") - parser_build = sub_parser.add_parser('build', - help=('Accepts a list of targets to build,' - ' or builds the entire project if no target is given'), - formatter_class=argparse.RawTextHelpFormatter) - parser_build.add_argument('build', - help=('Build the entire project or the specified target and its dependencies.\n' - 'To get the list of targets, use:\n' - './ns3 show targets\n'), - action="store", nargs='*', default=None, metavar='target') + parser_build = sub_parser.add_parser( + "build", + help=( + "Accepts a list of targets to build," + " or builds the entire project if no target is given" + ), + formatter_class=argparse.RawTextHelpFormatter, + ) + parser_build.add_argument( + "build", + help=( + "Build the entire project or the specified target and its dependencies.\n" + "To get the list of targets, use:\n" + "./ns3 show targets\n" + ), + action="store", + nargs="*", + default=None, + metavar="target", + ) - parser_configure = sub_parser.add_parser('configure', - help='Try "./ns3 configure --help" for more configuration options') - parser_configure.add_argument('configure', - action='store_true', default=False) - parser_configure.add_argument('-d', '--build-profile', - help='Build profile', - dest='build_profile', - choices=["debug", "default", "release", "optimized", "minsizerel"], - action="store", type=str, default=None) + parser_configure = sub_parser.add_parser( + "configure", help='Try "./ns3 configure --help" for more configuration options' + ) + parser_configure.add_argument("configure", action="store_true", default=False) + parser_configure.add_argument( + "-d", + "--build-profile", + help="Build profile", + dest="build_profile", + choices=["debug", "default", "release", "optimized", "minsizerel"], + action="store", + type=str, + default=None, + ) - parser_configure.add_argument('-G', - help=('CMake generator ' - '(e.g. https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html)'), - action="store", type=str, default=None) + parser_configure.add_argument( + "-G", + help=( + "CMake generator " + "(e.g. https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html)" + ), + action="store", + type=str, + default=None, + ) - parser_configure.add_argument('--cxx-standard', - help='Compile NS-3 with the given C++ standard', - type=str, default=None) + parser_configure.add_argument( + "--cxx-standard", help="Compile NS-3 with the given C++ standard", type=str, default=None + ) # On-Off options # First positional is transformed into --enable-option --disable-option @@ -134,9 +170,11 @@ def parse_args(argv): # and the third is used as is as the 'disable' description on_off_options = [ ("asserts", "the asserts regardless of the compile mode"), - ("des-metrics", "Logging all events in a json file with the name of the executable " - "(which must call CommandLine::Parse(argc, argv))" - ), + ( + "des-metrics", + "Logging all events in a json file with the name of the executable " + "(which must call CommandLine::Parse(argc, argv))", + ), ("build-version", "embedding git changes as a build version during build"), ("clang-tidy", "clang-tidy static analysis"), ("dpdk", "the fd-net-device DPDK features"), @@ -149,181 +187,310 @@ def parse_args(argv): ("monolib", "a single shared library with all ns-3 modules"), ("mpi", "the MPI support for distributed simulation"), ("mtp", "Multithreading support for high speed parallel simulation"), - ("ninja-tracing", "the conversion of the Ninja generator log file into about://tracing format"), + ( + "ninja-tracing", + "the conversion of the Ninja generator log file into about://tracing format", + ), ("precompiled-headers", "precompiled headers"), ("python-bindings", "python bindings"), ("tests", "the ns-3 tests"), ("sanitizers", "address, memory leaks and undefined behavior sanitizers"), - ("static", "Build a single static library with all ns-3", - "Restore the shared libraries" - ), + ("static", "Build a single static library with all ns-3", "Restore the shared libraries"), ("sudo", "use of sudo to setup suid bits on ns3 executables."), ("verbose", "printing of additional build system messages"), ("warnings", "compiler warnings"), - ("werror", "Treat compiler warnings as errors", - "Treat compiler warnings as warnings" - ), + ("werror", "Treat compiler warnings as errors", "Treat compiler warnings as warnings"), ] for on_off_option in on_off_options: parser_configure = on_off_argument(parser_configure, *on_off_option) - parser_configure.add_argument('--enable-modules', - help='List of modules to build (e.g. \"core;network;internet\")', - action="store", type=str, default=None) - parser_configure.add_argument('--disable-modules', - help='List of modules not to build (e.g. \"lte;wimax\")', - action="store", type=str, default=None) - parser_configure.add_argument('--filter-module-examples-and-tests', - help=('List of modules that should have their examples ' - 'and tests built (e.g. \"lte;wifi\")'), - action="store", type=str, default=None) - parser_configure.add_argument('--lcov-report', - help=('Generate a code coverage report ' - '(use this option after configuring with --enable-gcov and running a program)'), - action="store_true", default=None) - parser_configure.add_argument('--lcov-zerocounters', - help=('Zero the lcov counters' - ' (use this option before rerunning a program' - ' when generating repeated lcov reports)'), - action="store_true", default=None) + parser_configure.add_argument( + "--enable-modules", + help='List of modules to build (e.g. "core;network;internet")', + action="store", + type=str, + default=None, + ) + parser_configure.add_argument( + "--disable-modules", + help='List of modules not to build (e.g. "lte;wimax")', + action="store", + type=str, + default=None, + ) + parser_configure.add_argument( + "--filter-module-examples-and-tests", + help=( + "List of modules that should have their examples " 'and tests built (e.g. "lte;wifi")' + ), + action="store", + type=str, + default=None, + ) + parser_configure.add_argument( + "--lcov-report", + help=( + "Generate a code coverage report " + "(use this option after configuring with --enable-gcov and running a program)" + ), + action="store_true", + default=None, + ) + parser_configure.add_argument( + "--lcov-zerocounters", + help=( + "Zero the lcov counters" + " (use this option before rerunning a program" + " when generating repeated lcov reports)" + ), + action="store_true", + default=None, + ) - parser_configure.add_argument('--out', '--output-directory', - help=('Directory to store build artifacts'), - type=str, default=None, dest="output_directory") - parser_configure.add_argument('--with-brite', - help=('Use BRITE integration support, given by the indicated path,' - ' to allow the use of the BRITE topology generator'), - type=str, default=None) - parser_configure.add_argument('--with-click', - help='Path to Click source or installation prefix for NS-3 Click Integration support', - type=str, default=None) - parser_configure.add_argument('--with-openflow', - help='Path to OFSID source for NS-3 OpenFlow Integration support', - type=str, default=None) - parser_configure.add_argument('--force-refresh', - help='Force refresh the CMake cache by deleting' - ' the cache and reconfiguring the project', - action="store_true", default=None) - parser_configure.add_argument('--prefix', - help='Target output directory to install', - action="store", default=None) - parser_configure.add_argument('--trace-performance', - help="Generate a performance trace log for the CMake configuration", - action="store_true", default=None, dest="trace_cmake_perf") + parser_configure.add_argument( + "--out", + "--output-directory", + help=("Directory to store build artifacts"), + type=str, + default=None, + dest="output_directory", + ) + parser_configure.add_argument( + "--with-brite", + help=( + "Use BRITE integration support, given by the indicated path," + " to allow the use of the BRITE topology generator" + ), + type=str, + default=None, + ) + parser_configure.add_argument( + "--with-click", + help="Path to Click source or installation prefix for NS-3 Click Integration support", + type=str, + default=None, + ) + parser_configure.add_argument( + "--with-openflow", + help="Path to OFSID source for NS-3 OpenFlow Integration support", + type=str, + default=None, + ) + parser_configure.add_argument( + "--force-refresh", + help="Force refresh the CMake cache by deleting" " the cache and reconfiguring the project", + action="store_true", + default=None, + ) + parser_configure.add_argument( + "--prefix", help="Target output directory to install", action="store", default=None + ) + parser_configure.add_argument( + "--trace-performance", + help="Generate a performance trace log for the CMake configuration", + action="store_true", + default=None, + dest="trace_cmake_perf", + ) - parser_clean = sub_parser.add_parser('clean', help='Removes files created by ns3') - parser_clean.add_argument('clean', action="store_true", default=False) + parser_clean = sub_parser.add_parser("clean", help="Removes files created by ns3") + parser_clean.add_argument("clean", action="store_true", default=False) - parser_distclean = sub_parser.add_parser('distclean', help='Removes files created by ns3, tests and documentation') - parser_distclean.add_argument('distclean', action="store_true", default=False) + parser_distclean = sub_parser.add_parser( + "distclean", help="Removes files created by ns3, tests and documentation" + ) + parser_distclean.add_argument("distclean", action="store_true", default=False) - parser_install = sub_parser.add_parser('install', help='Install ns-3') - parser_install.add_argument('install', action="store_true", default=False) + parser_install = sub_parser.add_parser("install", help="Install ns-3") + parser_install.add_argument("install", action="store_true", default=False) - parser_uninstall = sub_parser.add_parser('uninstall', help='Uninstall ns-3') - parser_uninstall.add_argument('uninstall', action="store_true", default=False) + parser_uninstall = sub_parser.add_parser("uninstall", help="Uninstall ns-3") + parser_uninstall.add_argument("uninstall", action="store_true", default=False) - parser_run = sub_parser.add_parser('run', - help='Try "./ns3 run --help" for more runtime options', - formatter_class=argparse.RawTextHelpFormatter) - parser_run.add_argument('run', - help=('Build and run the target executable.\n' - 'If --no-build is present, the build step is skipped.\n' - 'To get the list of targets, use:\n' - './ns3 show targets\n' - 'Arguments can be passed down to a program in one of the following ways:\n' - './ns3 run "target --help"\n' - './ns3 run target -- --help\n' - './ns3 run target --command-template="%%s --help"\n'), - default='', nargs='?', metavar='target') - parser_run.add_argument('--no-build', - help='Skip build step.', - action="store_true", default=False) - parser_run.add_argument('--command-template', - help=('Template of the command used to run the program given by run;' - ' It should be a shell command string containing %%s inside,' - ' which will be replaced by the actual program.'), - type=str, default=None) - parser_run.add_argument('--cwd', - help='Set the working directory for a program.', - action="store", type=str, default=None) - parser_run.add_argument('--gdb', - help='Change the default command template to run programs with gdb', - action="store_true", default=None) - parser_run.add_argument('--lldb', - help='Change the default command template to run programs with lldb', - action="store_true", default=None) - parser_run.add_argument('-g', '--valgrind', - help='Change the default command template to run programs with valgrind', - action="store_true", default=None) - parser_run.add_argument('--memray', - help='Use Memray memory profiler for Python scripts. Output will be saved to memray.output', - action="store_true", default=None) - parser_run.add_argument('--heaptrack', - help='Use Heaptrack memory profiler for C++', - action="store_true", default=None) - parser_run.add_argument('--perf', - help='Use Linux\'s perf to profile a program', - action="store_true", default=None) - parser_run.add_argument('--vis', '--visualize', - help='Modify --run arguments to enable the visualizer', - action="store_true", dest="visualize", default=None) - parser_run.add_argument('--enable-sudo', - help='Use sudo to setup suid bits on ns3 executables.', - dest='enable_sudo', action='store_true', - default=False) + parser_run = sub_parser.add_parser( + "run", + help='Try "./ns3 run --help" for more runtime options', + formatter_class=argparse.RawTextHelpFormatter, + ) + parser_run.add_argument( + "run", + help=( + "Build and run the target executable.\n" + "If --no-build is present, the build step is skipped.\n" + "To get the list of targets, use:\n" + "./ns3 show targets\n" + "Arguments can be passed down to a program in one of the following ways:\n" + './ns3 run "target --help"\n' + "./ns3 run target -- --help\n" + './ns3 run target --command-template="%%s --help"\n' + ), + default="", + nargs="?", + metavar="target", + ) + parser_run.add_argument( + "--no-build", help="Skip build step.", action="store_true", default=False + ) + parser_run.add_argument( + "--command-template", + help=( + "Template of the command used to run the program given by run;" + " It should be a shell command string containing %%s inside," + " which will be replaced by the actual program." + ), + type=str, + default=None, + ) + parser_run.add_argument( + "--cwd", + help="Set the working directory for a program.", + action="store", + type=str, + default=None, + ) + parser_run.add_argument( + "--gdb", + help="Change the default command template to run programs with gdb", + action="store_true", + default=None, + ) + parser_run.add_argument( + "--lldb", + help="Change the default command template to run programs with lldb", + action="store_true", + default=None, + ) + parser_run.add_argument( + "-g", + "--valgrind", + help="Change the default command template to run programs with valgrind", + action="store_true", + default=None, + ) + parser_run.add_argument( + "--memray", + help="Use Memray memory profiler for Python scripts. Output will be saved to memray.output", + action="store_true", + default=None, + ) + parser_run.add_argument( + "--heaptrack", + help="Use Heaptrack memory profiler for C++", + action="store_true", + default=None, + ) + parser_run.add_argument( + "--perf", help="Use Linux's perf to profile a program", action="store_true", default=None + ) + parser_run.add_argument( + "--vis", + "--visualize", + help="Modify --run arguments to enable the visualizer", + action="store_true", + dest="visualize", + default=None, + ) + parser_run.add_argument( + "--enable-sudo", + help="Use sudo to setup suid bits on ns3 executables.", + dest="enable_sudo", + action="store_true", + default=False, + ) - parser_shell = sub_parser.add_parser('shell', - help='Try "./ns3 shell --help" for more shell options') - parser_shell.add_argument('shell', - help='Export necessary environment variables and open a shell', - action="store_true", default=False) + parser_shell = sub_parser.add_parser( + "shell", help='Try "./ns3 shell --help" for more shell options' + ) + parser_shell.add_argument( + "shell", + help="Export necessary environment variables and open a shell", + action="store_true", + default=False, + ) - parser_docs = sub_parser.add_parser('docs', - help='Try "./ns3 docs --help" for more documentation options') - parser_docs.add_argument('docs', - help='Build project documentation', - choices=["contributing", "installation", "manual", "models", "tutorial", - "sphinx", "doxygen-no-build", "doxygen", "all"], - action="store", type=str, default=None) + parser_docs = sub_parser.add_parser( + "docs", help='Try "./ns3 docs --help" for more documentation options' + ) + parser_docs.add_argument( + "docs", + help="Build project documentation", + choices=[ + "contributing", + "installation", + "manual", + "models", + "tutorial", + "sphinx", + "doxygen-no-build", + "doxygen", + "all", + ], + action="store", + type=str, + default=None, + ) - parser_show = sub_parser.add_parser('show', - help='Try "./ns3 show --help" for more show options') - parser_show.add_argument('show', - help=('Print the current ns-3 build profile type, configuration or version, ' - 'or a list of buildable/runnable targets'), - choices=["profile", "version", "config", "targets", "all"], - action="store", type=str, nargs="?", default="all") + parser_show = sub_parser.add_parser( + "show", help='Try "./ns3 show --help" for more show options' + ) + parser_show.add_argument( + "show", + help=( + "Print the current ns-3 build profile type, configuration or version, " + "or a list of buildable/runnable targets" + ), + choices=["profile", "version", "config", "targets", "all"], + action="store", + type=str, + nargs="?", + default="all", + ) add_argument_to_subparsers( - [parser, parser_build, parser_configure, parser_clean, parser_distclean, parser_docs, parser_run, parser_show], + [ + parser, + parser_build, + parser_configure, + parser_clean, + parser_distclean, + parser_docs, + parser_run, + parser_show, + ], ["--dry-run"], help_msg="Do not execute the commands.", - dest="dry_run") + dest="dry_run", + ) - add_argument_to_subparsers([parser, parser_build, parser_run], - ['-j', '--jobs'], - help_msg="Set number of parallel jobs.", - dest="jobs", - action="store", - default_value=max_cpu_threads) + add_argument_to_subparsers( + [parser, parser_build, parser_run], + ["-j", "--jobs"], + help_msg="Set number of parallel jobs.", + dest="jobs", + action="store", + default_value=max_cpu_threads, + ) - add_argument_to_subparsers([parser, parser_build, parser_configure, parser_run, parser_show], - ["--quiet"], - help_msg="Don't print task lines, i.e. messages saying which tasks are being executed.", - dest="quiet") + add_argument_to_subparsers( + [parser, parser_build, parser_configure, parser_run, parser_show], + ["--quiet"], + help_msg="Don't print task lines, i.e. messages saying which tasks are being executed.", + dest="quiet", + ) - add_argument_to_subparsers([parser, parser_build, parser_configure, parser_docs, parser_run], - ['-v', '--verbose'], - help_msg='Print which commands were executed', - dest='verbose', - default_value=False) + add_argument_to_subparsers( + [parser, parser_build, parser_configure, parser_docs, parser_run], + ["-v", "--verbose"], + help_msg="Print which commands were executed", + dest="verbose", + default_value=False, + ) # Try to split -- separated arguments into two lists for ns3 and for the runnable target try: - args_separator_index = argv.index('--') + args_separator_index = argv.index("--") ns3_args = argv[:args_separator_index] - runnable_args = argv[args_separator_index + 1:] + runnable_args = argv[args_separator_index + 1 :] except ValueError: ns3_args = argv runnable_args = [] @@ -332,17 +499,19 @@ def parse_args(argv): args, unknown_args = parser.parse_known_args(ns3_args) # If run doesn't have a target, print the help message of the run parser - if "run" in args and args.run == '': + if "run" in args and args.run == "": parser_run.print_help() exit(-1) # Merge attributes attributes_to_merge = ["dry_run", "help", "verbose", "quiet"] filtered_attributes = list( - filter(lambda x: x if ("disable" not in x and "enable" not in x) else None, args.__dir__())) + filter(lambda x: x if ("disable" not in x and "enable" not in x) else None, args.__dir__()) + ) for attribute in attributes_to_merge: merging_attributes = list( - map(lambda x: args.__getattribute__(x) if attribute in x else None, filtered_attributes)) + map(lambda x: args.__getattribute__(x) if attribute in x else None, filtered_attributes) + ) setattr(args, attribute, merging_attributes.count(True) > 0) if args.help: @@ -352,8 +521,8 @@ def parse_args(argv): # retrieve subparsers from parser subparsers_actions = [ - action for action in parser._actions - if isinstance(action, argparse._SubParsersAction)] + action for action in parser._actions if isinstance(action, argparse._SubParsersAction) + ] # there will probably only be one subparser_action, # but better safe than sorry for subparsers_action in subparsers_actions: @@ -363,18 +532,36 @@ def parse_args(argv): if len(subcommand) > 1: print(subcommand) - print(parser.format_help().replace(parser.description, "").replace(parser.format_usage(), "")) + print( + parser.format_help().replace(parser.description, "").replace(parser.format_usage(), "") + ) exit(0) attributes_to_merge = ["jobs"] - filtered_attributes = list(filter(lambda x: x if ("disable" not in x and "enable" not in x) else 0, args.__dir__())) + filtered_attributes = list( + filter(lambda x: x if ("disable" not in x and "enable" not in x) else 0, args.__dir__()) + ) for attribute in attributes_to_merge: merging_attributes = list( - map(lambda x: int(args.__getattribute__(x)) if attribute in x else max_cpu_threads, filtered_attributes)) + map( + lambda x: int(args.__getattribute__(x)) if attribute in x else max_cpu_threads, + filtered_attributes, + ) + ) setattr(args, attribute, min(merging_attributes)) # If some positional options are not in args, set them to false. - for option in ["clean", "configure", "docs", "install", "run", "shell", "uninstall", "show", "distclean"]: + for option in [ + "clean", + "configure", + "docs", + "install", + "run", + "shell", + "uninstall", + "show", + "distclean", + ]: if option not in args: setattr(args, option, False) @@ -386,9 +573,11 @@ def parse_args(argv): # Emit error in case of unknown arguments if unknown_args: - msg = ("Unknown options were given: {options}.\n" - "To see the allowed options add the `--help` option.\n" - "To forward configuration or runtime options, put them after '--'.\n") + msg = ( + "Unknown options were given: {options}.\n" + "To see the allowed options add the `--help` option.\n" + "To forward configuration or runtime options, put them after '--'.\n" + ) if args.run: msg += "Try: ./ns3 run {target} -- {options}\n" if args.configure: @@ -403,14 +592,15 @@ def check_lock_data(output_directory): ns3_modules_tests = [] ns3_modules = None - build_info = {"NS3_ENABLED_MODULES": [], - "BUILD_PROFILE": None, - "VERSION": None, - "ENABLE_EXAMPLES": False, - "ENABLE_SUDO": False, - "ENABLE_TESTS": False, - "BUILD_VERSION_STRING": None - } + build_info = { + "NS3_ENABLED_MODULES": [], + "BUILD_PROFILE": None, + "VERSION": None, + "ENABLE_EXAMPLES": False, + "ENABLE_SUDO": False, + "ENABLE_TESTS": False, + "BUILD_VERSION_STRING": None, + } if output_directory and os.path.exists(lock_file): exec(open(lock_file).read(), globals(), build_info) ns3_modules = build_info["NS3_ENABLED_MODULES"] @@ -431,15 +621,18 @@ def print_and_buffer(message): def remove_dir(dir_to_remove, dry_run, directory_qualifier=""): dir_to_remove = os.path.abspath(dir_to_remove) if os.path.exists(dir_to_remove): - if (".." in os.path.relpath(dir_to_remove, ns3_path) - or os.path.abspath(dir_to_remove) == os.path.abspath(ns3_path)): + if ".." in os.path.relpath(dir_to_remove, ns3_path) or os.path.abspath( + dir_to_remove + ) == os.path.abspath(ns3_path): # In case the directory to remove isn't within # the current ns-3 directory, print an error # message for the dry-run case # Or throw an exception in a normal run - error_message = (f"The {directory_qualifier} directory '{dir_to_remove}' " - "is not within the current ns-3 directory. " - "Deleting it can cause data loss.") + error_message = ( + f"The {directory_qualifier} directory '{dir_to_remove}' " + "is not within the current ns-3 directory. " + "Deleting it can cause data loss." + ) if dry_run: print_and_buffer(error_message) return @@ -467,28 +660,29 @@ def clean_cmake_artifacts(dry_run=False): dirname = os.path.dirname(cmake_cache_file) remove_dir(dirname, dry_run, "CMake cache") - dirs_to_remove = [os.path.join(ns3_path, "testpy-output"), - os.path.join(ns3_path, "__pycache__") - ] - for dir_to_remove in dirs_to_remove: + dirs_to_remove = ["testpy-output", "__pycache__", "build", "cmake-cache"] + for dir_to_remove in map(append_to_ns3_path, dirs_to_remove): remove_dir(dir_to_remove, dry_run) remove_file(lock_file, dry_run) def clean_docs_and_tests_artifacts(dry_run=False): - docs_dir = os.path.join(ns3_path, 'doc') + docs_dir = append_to_ns3_path("doc") - file_artifacts = ["doxygen.log", - "doxygen.warnings.log", - "introspected-command-line.h", - "introspected-doxygen.h", - "ns3-object.txt"] + file_artifacts = [ + "doxygen.log", + "doxygen.warnings.log", + "introspected-command-line.h", + "introspected-doxygen.h", + "ns3-object.txt", + ] docs_files = [os.path.join(docs_dir, filename) for filename in file_artifacts] - docs_and_tests_dirs = [os.path.join(docs_dir, "html"), - os.path.join(docs_dir, "html-warn"), - ] + docs_and_tests_dirs = [ + os.path.join(docs_dir, "html"), + os.path.join(docs_dir, "html-warn"), + ] docs_and_tests_dirs.extend(glob.glob(f"{docs_dir}/**/build", recursive=True)) docs_and_tests_dirs.extend(glob.glob(f"{docs_dir}/**/source-temp", recursive=True)) @@ -500,16 +694,13 @@ def clean_docs_and_tests_artifacts(dry_run=False): def clean_pip_packaging_artifacts(dry_run=False): - pip_dirs = [os.path.join(ns3_path, "dist"), - os.path.join(ns3_path, "nsnam.egg-info"), - os.path.join(ns3_path, "wheelhouse") - ] - for directory in pip_dirs: + pip_dirs = ["dist", "nsnam.egg-info", "wheelhouse"] + for directory in map(append_to_ns3_path, pip_dirs): remove_dir(directory, dry_run) def clean_vcpkg_artifacts(dry_run=False): - remove_dir(os.path.join(ns3_path, "vcpkg"), dry_run) + remove_dir(append_to_ns3_path("vcpkg"), dry_run) def search_cmake_cache(build_profile): @@ -553,10 +744,7 @@ def search_cmake_cache(build_profile): if not current_cmake_generator: # Search for available generators - cmake_generator_map = {"ninja": "Ninja", - "make": "Unix Makefiles", - "xcodebuild": "Xcode" - } + cmake_generator_map = {"ninja": "Ninja", "make": "Unix Makefiles", "xcodebuild": "Xcode"} available_generators = [] for generator in cmake_generator_map.keys(): if shutil.which(generator): @@ -596,9 +784,11 @@ def project_configured(current_cmake_cache_folder): return True -def configure_cmake(cmake, args, current_cmake_cache_folder, current_cmake_generator, output, dry_run=False): +def configure_cmake( + cmake, args, current_cmake_cache_folder, current_cmake_generator, output, dry_run=False +): # Aggregate all flags to configure CMake - cmake_args = [cmake] + cmake_args = [cmake, "-S", ns3_path] if not project_configured(current_cmake_cache_folder): # Create a new cmake_cache folder if one does not exist @@ -620,10 +810,13 @@ def configure_cmake(cmake, args, current_cmake_cache_folder, current_cmake_gener # CMake with the respective installation if args.enable_python_bindings is True: import sysconfig + cmake_args.append(f"-DPython3_LIBRARY_DIRS={sysconfig.get_config_var('LIBDIR')}") cmake_args.append(f"-DPython3_INCLUDE_DIRS={sysconfig.get_config_var('INCLUDEPY')}") cmake_args.append(f"-DPython3_EXECUTABLE={sys.executable}") + cmake_args.extend(["-B", current_cmake_cache_folder]) + # C++ standard if args.cxx_standard is not None: cmake_args.append("-DCMAKE_CXX_STANDARD=%s" % args.cxx_standard) @@ -631,55 +824,67 @@ def configure_cmake(cmake, args, current_cmake_cache_folder, current_cmake_gener # Build type if args.build_profile is not None: args.build_profile = args.build_profile.lower() - if args.build_profile not in ["debug", "default", "release", "optimized", "minsizerel", "relwithdebinfo"]: + if args.build_profile not in [ + "debug", + "default", + "release", + "optimized", + "minsizerel", + "relwithdebinfo", + ]: raise Exception("Unknown build type") else: if args.build_profile == "debug": cmake_args.extend( - "-DCMAKE_BUILD_TYPE=debug -DNS3_ASSERT=ON -DNS3_LOG=ON -DNS3_WARNINGS_AS_ERRORS=ON".split()) + "-DCMAKE_BUILD_TYPE=debug -DNS3_ASSERT=ON -DNS3_LOG=ON -DNS3_WARNINGS_AS_ERRORS=ON".split() + ) elif args.build_profile in ["default", "relwithdebinfo"]: cmake_args.extend( - "-DCMAKE_BUILD_TYPE=default -DNS3_ASSERT=ON -DNS3_LOG=ON -DNS3_WARNINGS_AS_ERRORS=OFF".split()) + "-DCMAKE_BUILD_TYPE=default -DNS3_ASSERT=ON -DNS3_LOG=ON -DNS3_WARNINGS_AS_ERRORS=OFF".split() + ) elif args.build_profile in ["release", "optimized"]: cmake_args.extend( - "-DCMAKE_BUILD_TYPE=release -DNS3_ASSERT=OFF -DNS3_LOG=OFF -DNS3_WARNINGS_AS_ERRORS=OFF".split()) + "-DCMAKE_BUILD_TYPE=release -DNS3_ASSERT=OFF -DNS3_LOG=OFF -DNS3_WARNINGS_AS_ERRORS=OFF".split() + ) else: cmake_args.extend( "-DCMAKE_BUILD_TYPE=minsizerel -DNS3_ASSERT=OFF -DNS3_LOG=OFF -DNS3_WARNINGS_AS_ERRORS=OFF".split() ) - cmake_args.append("-DNS3_NATIVE_OPTIMIZATIONS=%s" % on_off((args.build_profile == "optimized"))) + cmake_args.append( + "-DNS3_NATIVE_OPTIMIZATIONS=%s" % on_off((args.build_profile == "optimized")) + ) - options = (("ASSERT", "asserts"), - ("CLANG_TIDY", "clang_tidy"), - ("COVERAGE", "gcov"), - ("DES_METRICS", "des_metrics"), - ("DPDK", "dpdk"), - ("EIGEN", "eigen"), - ("ENABLE_BUILD_VERSION", "build_version"), - ("ENABLE_SUDO", "sudo"), - ("EXAMPLES", "examples"), - ("GSL", "gsl"), - ("GTK3", "gtk"), - ("LOG", "logs"), - ("MONOLIB", "monolib"), - ("MPI", "mpi"), - ("MTP", "mtp"), - ("NINJA_TRACING", "ninja_tracing"), - ("PRECOMPILE_HEADERS", "precompiled_headers"), - ("PYTHON_BINDINGS", "python_bindings"), - ("SANITIZE", "sanitizers"), - ("STATIC", "static"), - ("TESTS", "tests"), - ("VERBOSE", "verbose"), - ("WARNINGS", "warnings"), - ("WARNINGS_AS_ERRORS", "werror"), - ) - for (cmake_flag, option_name) in options: + options = ( + ("ASSERT", "asserts"), + ("CLANG_TIDY", "clang_tidy"), + ("COVERAGE", "gcov"), + ("DES_METRICS", "des_metrics"), + ("DPDK", "dpdk"), + ("EIGEN", "eigen"), + ("ENABLE_BUILD_VERSION", "build_version"), + ("ENABLE_SUDO", "sudo"), + ("EXAMPLES", "examples"), + ("GSL", "gsl"), + ("GTK3", "gtk"), + ("LOG", "logs"), + ("MONOLIB", "monolib"), + ("MPI", "mpi"), + ("MTP", "mtp"), + ("NINJA_TRACING", "ninja_tracing"), + ("PRECOMPILE_HEADERS", "precompiled_headers"), + ("PYTHON_BINDINGS", "python_bindings"), + ("SANITIZE", "sanitizers"), + ("STATIC", "static"), + ("TESTS", "tests"), + ("VERBOSE", "verbose"), + ("WARNINGS", "warnings"), + ("WARNINGS_AS_ERRORS", "werror"), + ) + for cmake_flag, option_name in options: arg = on_off_condition(args, cmake_flag, option_name) if arg: is_on = "=ON" in arg - reverse = arg.replace("=ON" if is_on else "=OFF", - "=OFF" if is_on else "=ON") + reverse = arg.replace("=ON" if is_on else "=OFF", "=OFF" if is_on else "=ON") if reverse in cmake_args: cmake_args.remove(reverse) cmake_args.append(arg) @@ -711,35 +916,35 @@ def configure_cmake(cmake, args, current_cmake_cache_folder, current_cmake_gener cmake_args.append("-DNS3_DISABLED_MODULES=%s" % args.disable_modules) if args.filter_module_examples_and_tests is not None: - cmake_args.append("-DNS3_FILTER_MODULE_EXAMPLES_AND_TESTS=%s" % args.filter_module_examples_and_tests) + cmake_args.append( + "-DNS3_FILTER_MODULE_EXAMPLES_AND_TESTS=%s" % args.filter_module_examples_and_tests + ) # Try to set specified generator (will probably fail if there is an old cache) if args.G: cmake_args.extend(["-G", args.G]) if args.trace_cmake_perf: - cmake_performance_trace = os.path.join(os.path.relpath(ns3_path, current_cmake_cache_folder), - "cmake_performance_trace.log") - cmake_args.extend(["--profiling-format=google-trace", - "--profiling-output=" + cmake_performance_trace]) + cmake_performance_trace = os.path.join( + os.path.relpath(ns3_path, ns3_path), "cmake_performance_trace.log" + ) + cmake_args.extend( + ["--profiling-format=google-trace", "--profiling-output=" + cmake_performance_trace] + ) + + # Enable warnings for uninitialized variable usage + cmake_args.append("--warn-uninitialized") # Append CMake flags passed using the -- separator cmake_args.extend(args.program_args) - # Configure cmake - cmake_args.append("..") # for now, assuming the cmake_cache directory is inside the ns-3-dev folder - # Echo out the configure command - print_and_buffer("cd %s; %s ; cd %s" % (os.path.relpath(current_cmake_cache_folder, ns3_path), - " ".join(cmake_args), - os.path.relpath(ns3_path, current_cmake_cache_folder) - ) - ) + print_and_buffer(" ".join(cmake_args)) # Run cmake if not dry_run: proc_env = os.environ.copy() - ret = subprocess.run(cmake_args, cwd=current_cmake_cache_folder, stdout=output, env=proc_env) + ret = subprocess.run(cmake_args, stdout=output, env=proc_env) if ret.returncode != 0: exit(ret.returncode) @@ -748,7 +953,7 @@ def configure_cmake(cmake, args, current_cmake_cache_folder, current_cmake_gener def update_scratches_list(current_cmake_cache_folder): # Store list of scratches to trigger a reconfiguration step if needed - current_scratch_sources = glob.glob(os.path.join(ns3_path, "scratch", "**", "*.cc"), recursive=True) + current_scratch_sources = glob.glob(append_to_ns3_path("scratch", "**", "*.cc"), recursive=True) with open(os.path.join(current_cmake_cache_folder, "ns3scratches"), "w") as f: f.write("\n".join(current_scratch_sources)) @@ -776,11 +981,13 @@ def get_program_shortcuts(build_profile, ns3_version): temp_path = program.replace(out_dir, "") # Sometimes Windows uses \\, sometimes / # quite the mess - temp_path = temp_path.split(os.sep if os.sep in temp_path else '/') + temp_path = temp_path.split(os.sep if os.sep in temp_path else "/") temp_path.pop(0) # remove first path separator # Remove version prefix and build type suffix from shortcuts (or keep them too?) - temp_path[-1] = temp_path[-1].replace("-" + build_profile, "").replace("ns" + ns3_version + "-", "") + temp_path[-1] = ( + temp_path[-1].replace("-" + build_profile, "").replace("ns" + ns3_version + "-", "") + ) # Deal with scratch subdirs if "scratch" in temp_path and len(temp_path) > 3: @@ -790,7 +997,7 @@ def get_program_shortcuts(build_profile, ns3_version): # Check if there is a .cc file for that specific program source_file_path = os.sep.join(temp_path) + ".cc" source_shortcut = False - if os.path.exists(os.path.join(ns3_path, source_file_path)): + if os.path.exists(append_to_ns3_path(source_file_path)): source_shortcut = True program = program.strip() @@ -831,11 +1038,11 @@ def get_program_shortcuts(build_profile, ns3_version): # Filter collisions collisions = list(filter(lambda x: x if len(x[1]) > 1 else None, longest_shortcut_map.items())) - for (colliding_shortcut, longest_shortcuts) in collisions: + for colliding_shortcut, longest_shortcuts in collisions: ns3_program_map[colliding_shortcut] = longest_shortcuts if programs_dict["ns3_runnable_scripts"]: - scratch_scripts = glob.glob(os.path.join(ns3_path, "scratch", "*.py"), recursive=True) + scratch_scripts = glob.glob(append_to_ns3_path("scratch", "*.py"), recursive=True) programs_dict["ns3_runnable_scripts"].extend(scratch_scripts) for program in programs_dict["ns3_runnable_scripts"]: @@ -856,37 +1063,41 @@ def parse_version(version_str): def cmake_check_version(): # Check CMake version + minimum_cmake_version = "3.13.0" cmake3 = shutil.which("cmake3") cmake = cmake3 if cmake3 else shutil.which("cmake") if not cmake: - print("Error: CMake not found; please install version 3.10 or greater, or modify", path_variable) + print( + f"Error: CMake not found; please install version {minimum_cmake_version} or greater, or modify {path_variable}" + ) exit(1) cmake = cmake.replace(".EXE", "").replace(".exe", "") # Trim cmake executable extension cmake_output = subprocess.check_output([cmake, "--version"]).decode("utf-8") version = re.findall("version (.*)", cmake_output)[0] - if parse_version(version) < parse_version("3.10.0"): - print("Error: CMake found at %s but version %s is older than 3.10" % (cmake, version)) + if parse_version(version) < parse_version(minimum_cmake_version): + print( + f"Error: CMake found at {cmake} but version {version} is older than {minimum_cmake_version}" + ) exit(1) return cmake, version -def cmake_build(current_cmake_cache_folder, output, jobs, target=None, dry_run=False, build_verbose=False): +def cmake_build( + current_cmake_cache_folder, output, jobs, target=None, dry_run=False, build_verbose=False +): cmake, version = cmake_check_version() - # Older CMake versions don't accept the number of jobs directly - jobs_part = ("-j %d" % jobs) if parse_version(version) >= parse_version("3.12.0") else "" - target_part = (" --target %s" % target) if target else "" - cmake_build_command = "%s --build . %s%s" % (cmake, jobs_part, target_part) + cmake_args = [cmake, "--build", current_cmake_cache_folder] + if jobs: + cmake_args.extend(["-j", str(jobs)]) - print_and_buffer("cd %s; %s ; cd %s" % (os.path.relpath(current_cmake_cache_folder, ns3_path), - cmake_build_command, - os.path.relpath(ns3_path, current_cmake_cache_folder) - ) - ) + if target: + cmake_args.extend(["--target", target]) + + print_and_buffer(" ".join(cmake_args)) if not dry_run: # Assume quiet is not enabled, and print things normally - kwargs = {"stdout": None, - "stderr": None} + kwargs = {"stdout": None, "stderr": None} proc_env = os.environ.copy() if build_verbose: @@ -900,11 +1111,11 @@ def cmake_build(current_cmake_cache_folder, output, jobs, target=None, dry_run=F kwargs["stdout"] = subprocess.PIPE kwargs["stderr"] = subprocess.PIPE - ret = subprocess.run(cmake_build_command.split(), - cwd=current_cmake_cache_folder, - env=proc_env, - **kwargs, - ) + ret = subprocess.run( + cmake_args, + env=proc_env, + **kwargs, + ) # Print errors in case compilation fails and output != None (quiet) if ret.returncode != 0 and output is not None: @@ -918,18 +1129,24 @@ def cmake_build(current_cmake_cache_folder, output, jobs, target=None, dry_run=F def extract_cmakecache_settings(current_cmake_cache_folder): try: - with open(current_cmake_cache_folder + os.sep + "CMakeCache.txt", "r", encoding="utf-8") as f: + with open( + current_cmake_cache_folder + os.sep + "CMakeCache.txt", "r", encoding="utf-8" + ) as f: contents = f.read() except FileNotFoundError as e: raise e current_settings = re.findall("(NS3_.*):.*=(.*)", contents) # extract NS3 specific settings - current_settings.extend(re.findall("(CMAKE_BUILD_TYPE):.*=(.*)", contents)) # extract build type + current_settings.extend( + re.findall("(CMAKE_BUILD_TYPE):.*=(.*)", contents) + ) # extract build type current_settings.extend(re.findall("(CMAKE_GENERATOR):.*=(.*)", contents)) # extract generator current_settings.extend(re.findall("(CMAKE_CXX_COMPILER):.*=(.*)", contents)) # C++ compiler current_settings.extend(re.findall("(CMAKE_CXX_FLAGS):.*=(.*)", contents)) # C++ flags current_settings.extend(re.findall("(CMAKE_C_COMPILER):.*=(.*)", contents)) # C compiler current_settings.extend(re.findall("(CMAKE_C_FLAGS):.*=(.*)", contents)) # C flags - current_settings.extend(re.findall("(CMAKE_INSTALL_PREFIX):.*=(.*)", contents)) # installation directory + current_settings.extend( + re.findall("(CMAKE_INSTALL_PREFIX):.*=(.*)", contents) + ) # installation directory # Transform list into dictionary settings_dictionary = dict(current_settings) @@ -941,6 +1158,7 @@ def extract_cmakecache_settings(current_cmake_cache_folder): def reconfigure_cmake_to_force_refresh(cmake, current_cmake_cache_folder, output, dry_run=False): import json + settings_bak_file = "settings.json" # Extract settings or recover from the backup @@ -969,11 +1187,14 @@ def reconfigure_cmake_to_force_refresh(cmake, current_cmake_cache_folder, output cmake_args.append("..") # Echo out the configure command - print_and_buffer("cd %s; %s ; cd %s" % (os.path.relpath(ns3_path, current_cmake_cache_folder), - " ".join(cmake_args), - os.path.relpath(current_cmake_cache_folder, ns3_path) - ) - ) + print_and_buffer( + "cd %s; %s ; cd %s" + % ( + os.path.relpath(ns3_path, current_cmake_cache_folder), + " ".join(cmake_args), + os.path.relpath(current_cmake_cache_folder, ns3_path), + ) + ) # Call cmake if not dry_run: @@ -983,8 +1204,10 @@ def reconfigure_cmake_to_force_refresh(cmake, current_cmake_cache_folder, output if ret.returncode == 0: os.remove(settings_bak_file) else: - raise Exception("Reconfiguring CMake to force refresh failed. " - "A backup of the settings was saved in %s" % settings_bak_file) + raise Exception( + "Reconfiguring CMake to force refresh failed. " + "A backup of the settings was saved in %s" % settings_bak_file + ) update_scratches_list(current_cmake_cache_folder) @@ -997,7 +1220,9 @@ def get_target_to_build(program_path, ns3_version, build_profile): program_name = "" try: - program_name = "".join(*re.findall("(.*)ns%s-(.*)%s" % (ns3_version, build_profile_suffix), program_path)) + program_name = "".join( + *re.findall("(.*)ns%s-(.*)%s" % (ns3_version, build_profile_suffix), program_path) + ) except TypeError: print("Target to build does not exist: %s" % program_path) exit(1) @@ -1011,8 +1236,9 @@ def get_target_to_build(program_path, ns3_version, build_profile): return program_name.split("/")[-1] -def configuration_step(current_cmake_cache_folder, current_cmake_generator, args, - output, dry_run=False): +def configuration_step( + current_cmake_cache_folder, current_cmake_generator, args, output, dry_run=False +): # Search for the CMake binary cmake, _ = cmake_check_version() @@ -1023,55 +1249,56 @@ def configuration_step(current_cmake_cache_folder, current_cmake_generator, args exit(0) # Call cmake to configure/reconfigure/refresh the project - configure_cmake(cmake, - args, - current_cmake_cache_folder, - current_cmake_generator, - output, - dry_run - ) + configure_cmake( + cmake, args, current_cmake_cache_folder, current_cmake_generator, output, dry_run + ) # If manually configuring, we end the script earlier exit(0) -def build_step(args, - build_and_run, - target_to_run, - current_cmake_cache_folder, - ns3_modules, - ns3_version, - build_profile, - output): +def build_step( + args, + build_and_run, + target_to_run, + current_cmake_cache_folder, + ns3_modules, + ns3_version, + build_profile, + output, +): # There is one scenario where we build everything: ./ns3 build if "build" in args and len(args.build) == 0: - cmake_build(current_cmake_cache_folder, - jobs=args.jobs, - output=output, - dry_run=args.dry_run, - build_verbose=args.verbose - ) + cmake_build( + current_cmake_cache_folder, + jobs=args.jobs, + output=output, + dry_run=args.dry_run, + build_verbose=args.verbose, + ) # If we are building specific targets, we build them one by one if "build" in args: - non_executable_targets = ["assemble-introspected-command-line", - "check-version", - "cmake-format", - "coverage_gcc", - "docs", - "doxygen", - "doxygen-no-build", - "installation", - "sphinx", - "manual", - "models", - "ninjaTrace", - "timeTraceReport", - "tutorial", - "contributing", - "install", - "uninstall", - ] + non_executable_targets = [ + "assemble-introspected-command-line", + "check-version", + "cmake-format", + "cmake-format-check", + "coverage_gcc", + "docs", + "doxygen", + "doxygen-no-build", + "installation", + "sphinx", + "manual", + "models", + "ninjaTrace", + "timeTraceReport", + "tutorial", + "contributing", + "install", + "uninstall", + ] # Build targets in the list for target in args.build: if target in ns3_modules: @@ -1092,22 +1319,25 @@ def build_step(args, global run_verbose run_verbose = False # Do not print the equivalent cmake command - cmake_build(current_cmake_cache_folder, - jobs=args.jobs, - target=target, - output=output, - dry_run=args.dry_run, - build_verbose=args.verbose) + cmake_build( + current_cmake_cache_folder, + jobs=args.jobs, + target=target, + output=output, + dry_run=args.dry_run, + build_verbose=args.verbose, + ) # The remaining case is when we want to build something to run if build_and_run: - cmake_build(current_cmake_cache_folder, - jobs=args.jobs, - target=get_target_to_build(target_to_run, ns3_version, build_profile), - output=output, - dry_run=args.dry_run, - build_verbose=args.verbose - ) + cmake_build( + current_cmake_cache_folder, + jobs=args.jobs, + target=get_target_to_build(target_to_run, ns3_version, build_profile), + output=output, + dry_run=args.dry_run, + build_verbose=args.verbose, + ) def check_program_installed(program_name: str) -> str: @@ -1120,6 +1350,7 @@ def check_program_installed(program_name: str) -> str: def check_module_installed(module_name: str): import importlib + try: importlib.import_module(module_name) except ImportError: @@ -1130,14 +1361,15 @@ def check_module_installed(module_name: str): def run_step(args, target_to_run, target_args): libdir = "%s/lib" % out_dir - custom_env = {"PATH": libdir, - "PYTHONPATH": "%s/bindings/python" % out_dir, - } + custom_env = { + "PATH": libdir, + "PYTHONPATH": "%s/bindings/python" % out_dir, + } if sys.platform != "win32": custom_env["LD_LIBRARY_PATH"] = libdir proc_env = os.environ.copy() - for (key, value) in custom_env.items(): + for key, value in custom_env.items(): if key in proc_env: proc_env[key] += path_sep + value else: @@ -1160,7 +1392,14 @@ def run_step(args, target_to_run, target_args): # running with memray? if args.memray: check_module_installed("memray") - target_args = ["-m", "memray", "run", "-o", "memray.output", "--native"] + target_args + target_args = [ + "-m", + "memray", + "run", + "-o", + "memray.output", + "--native", + ] + target_args # running from ns-3-dev (ns3_path) or cwd if args.cwd: @@ -1173,7 +1412,8 @@ def run_step(args, target_to_run, target_args): # running valgrind? if args.valgrind: debugging_software.extend( - [check_program_installed("valgrind"), "--leak-check=full", "--show-leak-kinds=all"]) + [check_program_installed("valgrind"), "--leak-check=full", "--show-leak-kinds=all"] + ) # running gdb? if args.gdb: @@ -1188,11 +1428,16 @@ def run_step(args, target_to_run, target_args): # running with perf? if args.perf: - debugging_software.extend([ - check_program_installed("perf"), - "record", "--call-graph", "dwarf", "-e", - "cache-misses,branch-misses,cpu-cycles,stalled-cycles-frontend,stalled-cycles-backend" - ]) + debugging_software.extend( + [ + check_program_installed("perf"), + "record", + "--call-graph", + "dwarf", + "-e", + "cache-misses,branch-misses,cpu-cycles,stalled-cycles-frontend,stalled-cycles-backend", + ] + ) # running with the visualizer? if args.visualize: @@ -1215,24 +1460,31 @@ def run_step(args, target_to_run, target_args): if run_verbose or args.dry_run: exported_variables = "export " - for (variable, value) in custom_env.items(): + for variable, value in custom_env.items(): if variable == "PATH": value = path_variable + path_sep + libdir exported_variables += "%s=%s " % (variable, value) - print_and_buffer("cd %s; %s; %s" % (os.path.relpath(ns3_path, working_dir), - exported_variables, - " ".join(program_arguments) - ) - ) + print_and_buffer( + "cd %s; %s; %s" + % ( + os.path.relpath(ns3_path, working_dir), + exported_variables, + " ".join(program_arguments), + ) + ) if not args.dry_run: try: - subprocess.run(program_arguments, env=proc_env, cwd=working_dir, shell=use_shell, check=True) + subprocess.run( + program_arguments, env=proc_env, cwd=working_dir, shell=use_shell, check=True + ) except subprocess.CalledProcessError as e: # Replace list of arguments with a single string e.cmd = " ".join(e.cmd) # Replace full path to binary to relative path - e.cmd = e.cmd.replace(os.path.abspath(target_to_run), os.path.relpath(target_to_run, ns3_path)) + e.cmd = e.cmd.replace( + os.path.abspath(target_to_run), os.path.relpath(target_to_run, ns3_path) + ) # Print error message and forward the return code print(e) exit(e.returncode) @@ -1246,7 +1498,7 @@ def run_step(args, target_to_run, target_args): def non_ambiguous_program_target_list(programs: dict) -> list: # Assembles a dictionary of all the possible shortcuts a program have list_of_shortcuts = {} - for (shortcut, possible_programs) in programs.items(): + for shortcut, possible_programs in programs.items(): if len(possible_programs) == 1: if possible_programs[0] not in list_of_shortcuts: list_of_shortcuts[possible_programs[0]] = [shortcut] @@ -1296,11 +1548,13 @@ def print_targets_list(ns3_modules: list, ns3_programs: dict) -> None: output += large_item + "\n" return output - print("""Buildable targets:{buildables}\n\nRunnable/Buildable targets:{runnables} - """.format(buildables=list_to_table(sorted(ns3_modules)), - runnables=list_to_table(non_ambiguous_program_target_list(ns3_programs)) - ) - ) + print( + """Buildable targets:{buildables}\n\nRunnable/Buildable targets:{runnables} + """.format( + buildables=list_to_table(sorted(ns3_modules)), + runnables=list_to_table(non_ambiguous_program_target_list(ns3_programs)), + ) + ) return @@ -1318,16 +1572,26 @@ def show_build_version(build_version_string, exit_early=True): if build_version_string is None: project_not_configured() - if build_version_string == '' and shutil.which("git") and os.path.exists(os.path.join(ns3_path, ".git")): + if ( + build_version_string == "" + and shutil.which("git") + and os.path.exists(append_to_ns3_path(".git")) + ): try: - build_version_string = subprocess.check_output(["git", "describe", "--dirty"], cwd=ns3_path).decode() - build_version_string += ("Reconfigure with './ns3 configure --enable-build-version' " - "to bake the version into the libraries.") + build_version_string = subprocess.check_output( + ["git", "describe", "--dirty"], cwd=ns3_path + ).decode() + build_version_string += ( + "Reconfigure with './ns3 configure --enable-build-version' " + "to bake the version into the libraries." + ) except subprocess.CalledProcessError: pass - if build_version_string == '': - print("Build version feature disabled. Reconfigure ns-3 with ./ns3 configure --enable-build-version") + if build_version_string == "": + print( + "Build version feature disabled. Reconfigure ns-3 with ./ns3 configure --enable-build-version" + ) else: print("ns-3 version: %s" % build_version_string) @@ -1338,18 +1602,18 @@ def show_build_version(build_version_string, exit_early=True): # Debugging this with PyCharm is a no no. It refuses to work hanging indefinitely def sudo_command(command: list, password: str): # Run command and feed the sudo password - proc = subprocess.Popen(['sudo', '-S', *command], - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE - ).communicate(input=password.encode() + b'\n') + proc = subprocess.Popen( + ["sudo", "-S", *command], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ).communicate(input=password.encode() + b"\n") stdout, stderr = proc[0].decode(), proc[1].decode() # Clean sudo password after each command - subprocess.Popen(["sudo", "-k"], - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE).communicate() + subprocess.Popen( + ["sudo", "-k"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE + ).communicate() # Check if the password is wrong if "try again" in stderr: @@ -1374,9 +1638,11 @@ def sudo_step(args, target_to_run, configure_post_build: set): if not args.dry_run: if password is None: from getpass import getpass + password = getpass(prompt="Sudo password:") import stat + for target in targets_to_sudo: # Check if the file was already built if not os.path.exists(target): @@ -1409,7 +1675,9 @@ def refuse_run_as_root(): # Check if the user is root and refuse to run username = os.getenv("USER", "") if username == "root": - raise Exception("Refusing to run as root. --enable-sudo will request your password when needed") + raise Exception( + "Refusing to run as root. --enable-sudo will request your password when needed" + ) def main(): @@ -1424,7 +1692,7 @@ def main(): # If pybindgen exists in the parent directory # (e.g. ns3-all-in-one), add it to the PYTHONPATH - pybindgen_dir = glob.glob(os.path.abspath(os.path.join(ns3_path, "..", "pybindgen*"))) + pybindgen_dir = glob.glob(os.path.abspath(append_to_ns3_path("..", "pybindgen*"))) if pybindgen_dir: if "PYTHONPATH" not in os.environ: os.environ["PYTHONPATH"] = "" @@ -1459,9 +1727,9 @@ def main(): # Installation and uninstallation options become cmake targets if args.install: - args.build = ['install'] + args.build = ["install"] if args.uninstall: - args.build = ['uninstall'] + args.build = ["uninstall"] # Get build profile and other settings build_info, ns3_modules = check_lock_data(out_dir) @@ -1473,10 +1741,14 @@ def main(): # Docs subparser options become cmake targets if args.docs: args.build = [args.docs] if args.docs != "all" else ["sphinx", "doxygen"] - if "doxygen" in args.build and (not build_info["ENABLE_EXAMPLES"] or not build_info["ENABLE_TESTS"]): - print('The "./ns3 docs doxygen" and "./ns3 docs all" commands,\n' - 'requires examples and tests to generate introspected documentation.\n' - 'Try "./ns3 docs doxygen-no-build" or enable examples and tests.') + if "doxygen" in args.build and ( + not build_info["ENABLE_EXAMPLES"] or not build_info["ENABLE_TESTS"] + ): + print( + 'The "./ns3 docs doxygen" and "./ns3 docs all" commands,\n' + "requires examples and tests to generate introspected documentation.\n" + 'Try "./ns3 docs doxygen-no-build" or enable examples and tests.' + ) exit(1) if args.show == "profile": @@ -1505,7 +1777,7 @@ def main(): if len(target_to_run) > 0: # While testing a weird case appeared where the target to run is between quotes, # so we remove in case they exist - if target_to_run[0] in ["\"", "'"] and target_to_run[-1] in ["\"", "'"]: + if target_to_run[0] in ['"', "'"] and target_to_run[-1] in ['"', "'"]: target_to_run = target_to_run[1:-1] target_to_run = target_to_run.split() target_to_run, target_args = target_to_run[0], target_to_run[1:] @@ -1523,22 +1795,24 @@ def main(): # Check for changes in scratch sources and trigger a reconfiguration if sources changed if current_cmake_cache_folder: - current_scratch_sources = glob.glob(os.path.join(ns3_path, "scratch", "**", "*.cc"), - recursive=True) + current_scratch_sources = glob.glob( + append_to_ns3_path("scratch", "**", "*.cc"), recursive=True + ) scratches_file = os.path.join(current_cmake_cache_folder, "ns3scratches") if os.path.exists(scratches_file): with open(scratches_file, "r") as f: - previous_scratches_sources = f.read().split('\n') + previous_scratches_sources = f.read().split("\n") if previous_scratches_sources != current_scratch_sources: refresh_cmake(current_cmake_cache_folder, output) if args.configure: - configuration_step(current_cmake_cache_folder, - current_cmake_generator, - args, - output, - args.dry_run, - ) + configuration_step( + current_cmake_cache_folder, + current_cmake_generator, + args, + output, + args.dry_run, + ) if not project_configured(current_cmake_cache_folder): project_not_configured() @@ -1562,14 +1836,19 @@ def main(): check_config(current_cmake_cache_folder) print("---- Summary of buildable targets:") print("Buildable targets: %4.d" % len(ns3_modules)) - print("Runnable/Buildable targets: %4.d" % len(non_ambiguous_program_target_list(ns3_programs))) + print( + "Runnable/Buildable targets: %4.d" + % len(non_ambiguous_program_target_list(ns3_programs)) + ) exit(0) def check_ambiguous_target(target_type, target_to_check, programs): if len(programs[target_to_check]) > 1: - print('%s target "%s" is ambiguous. Try one of these: "%s"' - % (target_type, target_to_check, '", "'.join(programs[target_to_check]))) + print( + '%s target "%s" is ambiguous. Try one of these: "%s"' + % (target_type, target_to_check, '", "'.join(programs[target_to_check])) + ) exit(1) return programs[target_to_check][0] @@ -1586,33 +1865,46 @@ def main(): if "build" in args: complete_targets = [] for target in args.build: - build_target = check_ambiguous_target("Build", target, ns3_programs) if target in ns3_programs else target + build_target = ( + check_ambiguous_target("Build", target, ns3_programs) + if target in ns3_programs + else target + ) complete_targets.append(build_target) args.build = complete_targets del complete_targets if not run_only: - build_step(args, - build_and_run, - target_to_run, - current_cmake_cache_folder, - ns3_modules, - ns3_version, - build_profile, - output - ) + build_step( + args, + build_and_run, + target_to_run, + current_cmake_cache_folder, + ns3_modules, + ns3_version, + build_profile, + output, + ) if not args.shell and target_to_run and ".py" not in target_to_run: if sys.platform == "win32": target_to_run += ".exe" # If we're only trying to run the target, we need to check if it actually exists first - if (run_only or build_and_run) and ".py" not in target_to_run and not os.path.exists(target_to_run): + if ( + (run_only or build_and_run) + and ".py" not in target_to_run + and not os.path.exists(target_to_run) + ): raise Exception("Executable has not been built yet") # Setup program as sudo if enable_sudo or (args.run and args.enable_sudo): - sudo_step(args, target_to_run, set(map(lambda x: x[0], ns3_programs.values())) if enable_sudo else set()) + sudo_step( + args, + target_to_run, + set(map(lambda x: x[0], ns3_programs.values())) if enable_sudo else set(), + ) # Finally, we try to run it if args.shell or run_only or build_and_run: diff --git a/pyproject.toml b/pyproject.toml index a18eb14ff..18b1293c1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,3 +14,11 @@ local_scheme = "no-local-version" [tool.cibuildwheel] build-frontend = "build" + +[tool.black] +line-length = 100 +include = "\\bns3$|\\.py$" + +[tool.isort] +profile = "black" +line_length = 100 diff --git a/scratch/.gitignore b/scratch/.gitignore index 7d959a29d..64892bfaf 100644 --- a/scratch/.gitignore +++ b/scratch/.gitignore @@ -2,6 +2,7 @@ /* !.gitignore +!nested-subdir/ !subdir/ !scratch-simulator.cc !CMakeLists.txt diff --git a/scratch/CMakeLists.txt b/scratch/CMakeLists.txt index 093e79d7b..adeeb2cf8 100644 --- a/scratch/CMakeLists.txt +++ b/scratch/CMakeLists.txt @@ -14,14 +14,24 @@ function(create_scratch source_files) file(READ ${source_file} source_file_contents) string(REGEX MATCHALL "main[(| (]" main_position "${source_file_contents}") if(CMAKE_MATCH_0) - set(scratch_src ${source_file}) + list(APPEND scratch_src ${source_file}) endif() endforeach() - if(NOT scratch_src) - return() + list(LENGTH scratch_src scratch_src_len) + + # If there is no main function, raise an error + if(${scratch_src_len} EQUAL 0) + message(FATAL_ERROR "The following scratch source files do not contain a main function: ${source_files}") endif() + # If there are multiple main functions, raise an error + if(${scratch_src_len} GREATER 1) + message(FATAL_ERROR "The following scratch source files contain ${scratch_src_len} files with a main function: ${scratch_src}") + endif() + + # If there is a single main function, continue normally + # Get parent directory name get_filename_component(scratch_dirname ${scratch_src} DIRECTORY) string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}" "" scratch_dirname @@ -69,10 +79,9 @@ foreach(scratch_src ${single_source_file_scratches}) create_scratch(${scratch_src}) endforeach() -# Scan *.cc files in ns-3-dev/scratch subdirectories and build a target for each -# subdirectory +# Scan ns-3-dev/scratch subdirectories file( - GLOB_RECURSE scratch_subdirectories + GLOB scratch_subdirectories CONFIGURE_DEPENDS LIST_DIRECTORIES true ${CMAKE_CURRENT_SOURCE_DIR}/** @@ -84,6 +93,7 @@ foreach(entry ${scratch_subdirectories}) endif() endforeach() +# Build scratches per directory or following CMakeLists.txt instructions foreach(subdir ${scratch_subdirectories}) if(EXISTS ${subdir}/CMakeLists.txt) # If the subdirectory contains a CMakeLists.txt file diff --git a/setup.py b/setup.py index 8aa256955..31997e8f8 100644 --- a/setup.py +++ b/setup.py @@ -1,14 +1,15 @@ -import cmake_build_extension -import setuptools import sys import sysconfig +import cmake_build_extension +import setuptools + setuptools.setup( cmdclass=dict(build_ext=cmake_build_extension.BuildExtension), - packages=['ns', 'visualizer'], + packages=["ns", "visualizer"], package_dir={ - 'ns': './build-support/pip-wheel/ns', - 'visualizer': './build-support/pip-wheel/visualizer' + "ns": "./build-support/pip-wheel/ns", + "visualizer": "./build-support/pip-wheel/visualizer", }, ext_modules=[ cmake_build_extension.CMakeExtension( @@ -23,13 +24,12 @@ setuptools.setup( "-DNS3_BINDINGS_INSTALL_DIR:STRING=INSTALL_PREFIX", "-DNS3_FETCH_OPTIONAL_COMPONENTS:BOOL=ON", "-DNS3_PIP_PACKAGING:BOOL=ON", - "-DNS3_USE_LIB64:BOOL=ON", # Make CMake find python components from the currently running python # https://catherineh.github.io/programming/2021/11/16/python-binary-distributions-whls-with-c17-cmake-auditwheel-and-manylinux f"-DPython3_LIBRARY_DIRS={sysconfig.get_config_var('LIBDIR')}", f"-DPython3_INCLUDE_DIRS={sysconfig.get_config_var('INCLUDEPY')}", - f"-DPython3_EXECUTABLE={sys.executable}" - ] + f"-DPython3_EXECUTABLE={sys.executable}", + ], ), ], ) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f2d041ee4..d72e049a3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -15,9 +15,8 @@ foreach(libname ${libs}) message(STATUS "Processing src/${libname}") add_subdirectory(${libname}) else() - message( - ${HIGHLIGHTED_STATUS} - "Skipping src/${libname} : it does not contain a CMakeLists.txt file" + message(${HIGHLIGHTED_STATUS} + "Skipping src/${libname}: it does not contain a CMakeLists.txt file" ) endif() endforeach() diff --git a/src/antenna/doc/source/antenna-design.rst b/src/antenna/doc/source/antenna-design.rst index 0caeb6c6f..3d3087387 100644 --- a/src/antenna/doc/source/antenna-design.rst +++ b/src/antenna/doc/source/antenna-design.rst @@ -146,7 +146,7 @@ For details on Phased Array Antennas see for instance [Mailloux]_. Derived classes must implement the following functions: -* GetNumberOfElements: returns the number of antenna elements +* GetNumElems: returns the number of antenna elements * GetElementLocation: returns the location of the antenna element with the specified index, normalized with respect to the wavelength * GetElementFieldPattern: returns the horizontal and vertical components of the antenna element field pattern at the specified direction. Same polarization (configurable) for all antenna elements of the array is considered. @@ -160,10 +160,10 @@ UniformPlanarArray The class UniformPlanarArray is a generic implementation of Uniform Planar Arrays (UPAs), supporting rectangular and linear regular lattices. -It loosely follows the implementation described in the 3GPP TR 38.901 [38901]_, -considering only a single a single panel, i.e., :math:`N_{g} = M_{g} = 1`. +It closely follows the implementation described in the 3GPP TR 38.901 [38901]_, +considering only a single panel, i.e., :math:`N_{g} = M_{g} = 1`. -By default, the array is orthogonal to the x-axis, pointing towards the positive +By default, the antenna array is orthogonal to the x-axis, pointing towards the positive direction, but the orientation can be changed through the attributes "BearingAngle", which adjusts the azimuth angle, and "DowntiltAngle", which adjusts the elevation angle. The slant angle is instead fixed and assumed to be 0. @@ -173,8 +173,24 @@ through the attributes "NumRows" and "NumColumns", while the spacing between the and vertical elements can be configured through the attributes "AntennaHorizontalSpacing" and "AntennaVerticalSpacing". -The polarization of each antenna element in the array is determined by the polarization -slant angle through the attribute "PolSlantAngle", as described in [38901]_ (i.e., :math:`{\zeta}`). +UniformPlannarArray supports the concept of antenna ports following the sub-array partition +model for TXRU virtualization, as described in Section 5.2.2 of 3GPP TR 36.897 [36897]_. +The number of antenna ports in vertical and horizontal directions can be configured through +the attributes "NumVerticalPorts" and "NumHorizontalPorts", respectively. For example, +if "NumRows" and "NumColumns" are configured to 2 and 4, and the number of +"NumVerticalPorts" and "NumHorizontalPorts" to 1 and 2, then the antenna elements belonging +to the first two columns of the antenna array will belong to the first antenna port, +and the third and the fourth columns will belong to the second antenna port. Note that +"NumRows" and "NumColumns" must be a multiple of "NumVerticalPorts" and "NumHorizontalPorts", +respectively. + +Whether the antenna is dual-polarized or not is configured through the attribute +"IsDualPolarized". In case the antenna array is dual polarized, the total number +of antenna elements is doubled and the two polarizations are overlapped in space. +The polarization slant angle of the antenna elements belonging to the first polarization +are configured through the attribute "PolSlantAngle"; while the antenna elements of +the second polarization have the polarization slant angle minus 90 degrees, +as described in [38901]_ (i.e., :math:`{\zeta}`). .. [Balanis] C.A. Balanis, "Antenna Theory - Analysis and Design", Wiley, 2nd Ed. @@ -193,3 +209,6 @@ slant angle through the attribute "PolSlantAngle", as described in [38901]_ (i.e .. [38901] 3GPP. 2018. TR 38.901, Study on channel model for frequencies from 0.5 to 100 GHz, V15.0.0. (2018-06). .. [Mailloux] Robert J. Mailloux, "Phased Array Antenna Handbook", Artech House, 2nd Ed. + +.. [TR36897] 3GPP. 2015. TR 36.897. Study on elevation beamforming / Full-Dimension (FD) + Multiple Input Multiple Output (MIMO) for LTE. V13.0.0. (2015-06) diff --git a/src/antenna/doc/source/conf.py b/src/antenna/doc/source/conf.py index ad2f0c3ec..da78e5a8e 100644 --- a/src/antenna/doc/source/conf.py +++ b/src/antenna/doc/source/conf.py @@ -11,205 +11,209 @@ # All configuration values have a default; values that are commented out # serve to show the default. -import sys, os +import os +import sys # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('.')) +# sys.path.insert(0, os.path.abspath('.')) # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' +# needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.imgmath'] +extensions = ["sphinx.ext.imgmath"] # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # The suffix of source filenames. -source_suffix = '.rst' +source_suffix = ".rst" # The encoding of source files. -#source_encoding = 'utf-8-sig' +# source_encoding = 'utf-8-sig' # The master toctree document. -master_doc = 'index' +master_doc = "index" # General information about the project. -project = u'LENA' -copyright = u'2011-2012, CTTC' +project = "LENA" +copyright = "2011-2012, CTTC" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. -version = 'ns-3-dev' +version = "ns-3-dev" # The full version, including alpha/beta/rc tags. -release = 'ns-3-dev' +release = "ns-3-dev" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. -#language = None +# language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: -#today = '' +# today = '' # Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' +# today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = [] # The reST default role (used for this markup: `text`) to use for all documents. -#default_role = None +# default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True +# add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). -#add_module_names = True +# add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. -#show_authors = False +# show_authors = False # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +pygments_style = "sphinx" # A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] +# modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = 'default' +html_theme = "default" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. -#html_theme_options = {} +# html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] +# html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". -#html_title = None +# html_title = None # A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None +# html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. -#html_logo = None +# html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. -#html_favicon = None +# html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -#html_static_path = ['_static'] +# html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' +# html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. -#html_use_smartypants = True +# html_use_smartypants = True # Custom sidebar templates, maps document names to template names. -#html_sidebars = {} +# html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. -#html_additional_pages = {} +# html_additional_pages = {} # If false, no module index is generated. -#html_domain_indices = True +# html_domain_indices = True # If false, no index is generated. -#html_use_index = True +# html_use_index = True # If true, the index is split into individual pages for each letter. -#html_split_index = False +# html_split_index = False # If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True +# html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True +# html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True +# html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. -#html_use_opensearch = '' +# html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None +# html_file_suffix = None # Output file base name for HTML help builder. -#htmlhelp_basename = 'ns-3doc' +# htmlhelp_basename = 'ns-3doc' # -- Options for LaTeX output -------------------------------------------------- # The paper size ('letter' or 'a4'). -#latex_paper_size = 'letter' +# latex_paper_size = 'letter' # The font size ('10pt', '11pt' or '12pt'). -#latex_font_size = '10pt' +# latex_font_size = '10pt' # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ - ('antenna', 'antenna.tex', u'Antenna Module Documentation', u'Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)', 'manual'), + ( + "antenna", + "antenna.tex", + "Antenna Module Documentation", + "Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)", + "manual", + ), ] # The name of an image file (relative to this directory) to place at the top of # the title page. -#latex_logo = None +# latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. -#latex_use_parts = False +# latex_use_parts = False # If true, show page references after internal links. -#latex_show_pagerefs = False +# latex_show_pagerefs = False # If true, show URL addresses after external links. -#latex_show_urls = False +# latex_show_urls = False # Additional stuff for the LaTeX preamble. -#latex_preamble = '' +# latex_preamble = '' # Documents to append as an appendix to all manuals. -#latex_appendices = [] +# latex_appendices = [] # If false, no module index is generated. -#latex_domain_indices = True +# latex_domain_indices = True # -- Options for manual page output -------------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [ - ('index', 'ns-3-model-library', u'ns-3 Model Library', - [u'ns-3 project'], 1) -] +man_pages = [("index", "ns-3-model-library", "ns-3 Model Library", ["ns-3 project"], 1)] diff --git a/src/antenna/model/phased-array-model.cc b/src/antenna/model/phased-array-model.cc index 81477811d..46d950cbf 100644 --- a/src/antenna/model/phased-array-model.cc +++ b/src/antenna/model/phased-array-model.cc @@ -34,28 +34,6 @@ NS_LOG_COMPONENT_DEFINE("PhasedArrayModel"); NS_OBJECT_ENSURE_REGISTERED(PhasedArrayModel); -std::ostream& -operator<<(std::ostream& os, const PhasedArrayModel::ComplexVector& cv) -{ - size_t N = cv.GetSize(); - - // empty - if (N == 0) - { - os << "[]"; - return os; - } - - // non-empty - os << "["; - for (std::size_t i = 0; i < N - 1; ++i) - { - os << cv[i] << ", "; - } - os << cv[N - 1] << "]"; - return os; -} - PhasedArrayModel::PhasedArrayModel() : m_isBfVectorValid{false} { @@ -85,8 +63,8 @@ void PhasedArrayModel::SetBeamformingVector(const ComplexVector& beamformingVector) { NS_LOG_FUNCTION(this << beamformingVector); - NS_ASSERT_MSG(beamformingVector.GetSize() == GetNumberOfElements(), - beamformingVector.GetSize() << " != " << GetNumberOfElements()); + NS_ASSERT_MSG(beamformingVector.GetSize() == GetNumElems(), + beamformingVector.GetSize() << " != " << GetNumElems()); m_beamformingVector = beamformingVector; m_isBfVectorValid = true; } @@ -101,15 +79,32 @@ PhasedArrayModel::GetBeamformingVector() const return m_beamformingVector; } +const PhasedArrayModel::ComplexVector& +PhasedArrayModel::GetBeamformingVectorRef() const +{ + NS_LOG_FUNCTION(this); + NS_ASSERT_MSG(m_isBfVectorValid, + "The beamforming vector should be Set before it's Get, and should refer to the " + "current array configuration"); + return m_beamformingVector; +} + PhasedArrayModel::ComplexVector PhasedArrayModel::GetBeamformingVector(Angles a) const { NS_LOG_FUNCTION(this << a); ComplexVector beamformingVector = GetSteeringVector(a); - double normRes = norm(beamformingVector); + // The normalization takes into account the total number of ports as only a + // portion (K,L) of beam weights associated with a specific port are non-zero. + // See 3GPP Section 5.2.2 36.897. This normalization corresponds to + // a sub-array partition model (which is different from the full-connection + // model). Note that the total number of ports used to perform normalization + // is the ratio between the total number of antenna elements and the + // number of antenna elements per port. + double normRes = norm(beamformingVector) / sqrt(GetNumPorts()); - for (size_t i = 0; i < GetNumberOfElements(); i++) + for (size_t i = 0; i < GetNumElems(); i++) { beamformingVector[i] = std::conj(beamformingVector[i]) / normRes; } @@ -120,8 +115,8 @@ PhasedArrayModel::GetBeamformingVector(Angles a) const PhasedArrayModel::ComplexVector PhasedArrayModel::GetSteeringVector(Angles a) const { - ComplexVector steeringVector(GetNumberOfElements()); - for (size_t i = 0; i < GetNumberOfElements(); i++) + ComplexVector steeringVector(GetNumElems()); + for (size_t i = 0; i < GetNumElems(); i++) { Vector loc = GetElementLocation(i); double phase = -2 * M_PI * diff --git a/src/antenna/model/phased-array-model.h b/src/antenna/model/phased-array-model.h index e1129a80a..193200e05 100644 --- a/src/antenna/model/phased-array-model.h +++ b/src/antenna/model/phased-array-model.h @@ -73,17 +73,7 @@ class PhasedArrayModel : public Object } /** - * Returns the horizontal and vertical components of the antenna element field - * pattern at the specified direction. Single polarization is considered. - * \param a the angle indicating the interested direction - * \return a pair in which the first element is the horizontal component - * of the field pattern and the second element is the vertical - * component of the field pattern - */ - virtual std::pair GetElementFieldPattern(Angles a) const = 0; - - /** - * Returns the location of the antenna element with the specified + * \brief Returns the location of the antenna element with the specified * index, normalized with respect to the wavelength. * \param index the index of the antenna element * \return the 3D vector that represents the position of the element @@ -91,10 +81,128 @@ class PhasedArrayModel : public Object virtual Vector GetElementLocation(uint64_t index) const = 0; /** - * Returns the number of antenna elements + * \brief Returns the number of antenna elements * \return the number of antenna elements */ - virtual size_t GetNumberOfElements() const = 0; + virtual size_t GetNumElems() const = 0; + + /** + * \brief Returns the horizontal and vertical components of the antenna element field + * pattern at the specified direction. Single polarization is considered. + * \param a the angle indicating the interested direction + * \param polIndex the index of the polarization for which will be retrieved the field + * pattern + * \return a pair in which the first element is the horizontal component of the field + * pattern and the second element is the vertical component of the field pattern + */ + virtual std::pair GetElementFieldPattern(Angles a, + uint8_t polIndex = 0) const = 0; + + /** + * \brief Set the vertical number of ports + * \param nPorts the vertical number of ports + */ + virtual void SetNumVerticalPorts(uint16_t nPorts) = 0; + + /** + * \brief Set the horizontal number of ports + * \param nPorts the horizontal number of ports + */ + virtual void SetNumHorizontalPorts(uint16_t nPorts) = 0; + + /** + * \brief Get the vertical number of ports + * \return the vertical number of ports + */ + virtual uint16_t GetNumVerticalPorts() const = 0; + + /** + * \brief Get the horizontal number of ports + * \return the horizontal number of ports + */ + virtual uint16_t GetNumHorizontalPorts() const = 0; + + /** + * \brief Get the number of ports + * \return the number of ports + */ + virtual uint16_t GetNumPorts() const = 0; + + /** + * \brief Get the number of polarizations + * \return the number of polarizations + */ + virtual uint8_t GetNumPols() const = 0; + + /** + * \brief Get the vertical number of antenna elements per port + * \return the vertical number of antenna elements per port + */ + virtual size_t GetVElemsPerPort() const = 0; + /** + * \brief Get the horizontal number of antenna elements per port + * \return the horizontal number of antenna elements per port + */ + virtual size_t GetHElemsPerPort() const = 0; + + /** + * \brief Get the number of elements per port + * \return the number of elements per port + */ + virtual size_t GetNumElemsPerPort() const = 0; + + /** + * \brief Set the number of columns + * \param nColumns the number of columns to be set + */ + virtual void SetNumColumns(uint32_t nColumns) = 0; + + /** + * \brief Set the number of rows + * \param nRows the number of rows to be set + */ + virtual void SetNumRows(uint32_t nRows) = 0; + + /** + * \brief Get the number of columns + * \return the number of columns in the antenna array + */ + virtual uint32_t GetNumColumns() const = 0; + + /** + * \brief Get the number of rows + * \return the number of rows in the antenna array + */ + virtual uint32_t GetNumRows() const = 0; + + /** + * \brief Get the polarization slant angle + * \return the polarization slant angle + */ + virtual double GetPolSlant() const = 0; + + /** + * \brief Get the indication whether the antenna array is dual polarized + * \return Returns true if the antenna array is dual polarized + */ + virtual bool IsDualPol() const = 0; + + /** + * \brief Calculate the index in the antenna array from the port index and the element in the + * port + * \param portIndex the port index + * \param subElementIndex the element index in the port + * \return the antenna element index in the antenna array + */ + virtual uint16_t ArrayIndexFromPortIndex(uint16_t portIndex, + uint16_t subElementIndex) const = 0; + + /** + * Returns the index of the polarization to which belongs that antenna element + * \param elementIndex the antenna element for which will be returned the polarization index + * \return the polarization index + */ + virtual uint8_t GetElemPol(size_t elementIndex) const = 0; /** * Sets the beamforming vector to be used @@ -108,6 +216,12 @@ class PhasedArrayModel : public Object */ ComplexVector GetBeamformingVector() const; + /** + * Returns the const reference of the beamforming vector that is currently being used + * \return the const reference of the current beamforming vector + */ + const PhasedArrayModel::ComplexVector& GetBeamformingVectorRef() const; + /** * Returns the beamforming vector that points towards the specified position * \param a the beamforming angle @@ -149,15 +263,6 @@ class PhasedArrayModel : public Object uint32_t m_id{0}; //!< the ID of this antenna array instance }; -/** - * \brief Stream insertion operator. - * - * \param [in] os The reference to the output stream. - * \param [in] cv A vector of complex values. - * \returns The reference to the output stream. - */ -std::ostream& operator<<(std::ostream& os, const PhasedArrayModel::ComplexVector& cv); - } /* namespace ns3 */ #endif /* PHASED_ARRAY_MODEL_H */ diff --git a/src/antenna/model/uniform-planar-array.cc b/src/antenna/model/uniform-planar-array.cc index 0f5eafa6d..5debed34a 100644 --- a/src/antenna/model/uniform-planar-array.cc +++ b/src/antenna/model/uniform-planar-array.cc @@ -84,8 +84,27 @@ UniformPlanarArray::GetTypeId() .AddAttribute("PolSlantAngle", "The polarization slant angle in radians", DoubleValue(0.0), - MakeDoubleAccessor(&UniformPlanarArray::SetPolSlant), - MakeDoubleChecker(-M_PI, M_PI)); + MakeDoubleAccessor(&UniformPlanarArray::SetPolSlant, + &UniformPlanarArray::GetPolSlant), + MakeDoubleChecker(-M_PI, M_PI)) + .AddAttribute("NumVerticalPorts", + "Vertical number of ports", + UintegerValue(1), + MakeUintegerAccessor(&UniformPlanarArray::GetNumVerticalPorts, + &UniformPlanarArray::SetNumVerticalPorts), + MakeUintegerChecker()) + .AddAttribute("NumHorizontalPorts", + "Horizontal number of ports", + UintegerValue(1), + MakeUintegerAccessor(&UniformPlanarArray::GetNumHorizontalPorts, + &UniformPlanarArray::SetNumHorizontalPorts), + MakeUintegerChecker()) + .AddAttribute("IsDualPolarized", + "If true, dual polarized antenna", + BooleanValue(false), + MakeBooleanAccessor(&UniformPlanarArray::SetDualPol, + &UniformPlanarArray::IsDualPol), + MakeBooleanChecker()); return tid; } @@ -143,8 +162,8 @@ void UniformPlanarArray::SetPolSlant(double polSlant) { m_polSlant = polSlant; - m_cosPolSlant = cos(m_polSlant); - m_sinPolSlant = sin(m_polSlant); + m_cosPolSlant[0] = cos(m_polSlant); + m_sinPolSlant[0] = sin(m_polSlant); } void @@ -186,9 +205,10 @@ UniformPlanarArray::GetAntennaVerticalSpacing() const } std::pair -UniformPlanarArray::GetElementFieldPattern(Angles a) const +UniformPlanarArray::GetElementFieldPattern(Angles a, uint8_t polIndex) const { NS_LOG_FUNCTION(this << a); + NS_ASSERT_MSG(polIndex < GetNumPols(), "Polarization index can be 0 or 1."); // convert the theta and phi angles from GCS to LCS using eq. 7.1-7 and 7.1-8 in 3GPP TR 38.901 // NOTE we assume a fixed slant angle of 0 degrees @@ -208,8 +228,10 @@ UniformPlanarArray::GetElementFieldPattern(Angles a) const // NOTE: the slant angle (assumed to be 0) differs from the polarization slant angle // (m_polSlant, given by the attribute), in 3GPP TR 38.901 double aPrimeDb = m_antennaElement->GetGainDb(aPrime); - double fieldThetaPrime = pow(10, aPrimeDb / 20) * m_cosPolSlant; // convert to linear magnitude - double fieldPhiPrime = pow(10, aPrimeDb / 20) * m_sinPolSlant; // convert to linear magnitude + double fieldThetaPrime = + pow(10, aPrimeDb / 20) * m_cosPolSlant[polIndex]; // convert to linear magnitude + double fieldPhiPrime = + pow(10, aPrimeDb / 20) * m_sinPolSlant[polIndex]; // convert to linear magnitude // compute psi using eq. 7.1-15 in 3GPP TR 38.901, assuming that the slant // angle (gamma) is 0 @@ -232,13 +254,19 @@ Vector UniformPlanarArray::GetElementLocation(uint64_t index) const { NS_LOG_FUNCTION(this << index); - + uint64_t tmpIndex = index; + // for dual polarization, the top half corresponds to one polarization and + // lower half corresponds to the other polarization + if (m_isDualPolarized && tmpIndex >= m_numRows * m_numColumns) + { + tmpIndex -= m_numRows * m_numColumns; + } // compute the element coordinates in the LCS // assume the left bottom corner is (0,0,0), and the rectangular antenna array is on the y-z // plane. double xPrime = 0; - double yPrime = m_disH * (index % m_numColumns); - double zPrime = m_disV * floor(index / m_numColumns); + double yPrime = m_disH * (tmpIndex % m_numColumns); + double zPrime = m_disV * floor(tmpIndex / m_numColumns); // convert the coordinates to the GCS using the rotation matrix 7.1-4 in 3GPP // TR 38.901 @@ -249,10 +277,129 @@ UniformPlanarArray::GetElementLocation(uint64_t index) const return loc; } -size_t -UniformPlanarArray::GetNumberOfElements() const +uint8_t +UniformPlanarArray::GetNumPols() const { - return m_numRows * m_numColumns; + return m_isDualPolarized ? 2 : 1; +} + +size_t +UniformPlanarArray::GetNumElems() const +{ + // From 38.901 [M, N, P, Mg, Ng] = [m_numRows, m_numColumns, 2, 1, 1] + return GetNumPols() * m_numRows * m_numColumns; + // with dual polarization, the number of antenna elements double up +} + +void +UniformPlanarArray::SetNumVerticalPorts(uint16_t nPorts) +{ + NS_LOG_FUNCTION(this); + NS_ASSERT_MSG(nPorts > 0, "Ports should be greater than 0"); + NS_ASSERT_MSG(((m_numRows % nPorts) == 0), + "The number of vertical ports must divide number of rows"); + m_numVPorts = nPorts; +} + +void +UniformPlanarArray::SetNumHorizontalPorts(uint16_t nPorts) +{ + NS_ASSERT_MSG(nPorts > 0, "Ports should be greater than 0"); + NS_ASSERT_MSG(((m_numColumns % nPorts) == 0), + "The number of horizontal ports must divide number of columns"); + m_numHPorts = nPorts; +} + +uint16_t +UniformPlanarArray::GetNumVerticalPorts() const +{ + return m_numVPorts; +} + +uint16_t +UniformPlanarArray::GetNumHorizontalPorts() const +{ + return m_numHPorts; +} + +uint16_t +UniformPlanarArray::GetNumPorts() const +{ + return GetNumPols() * m_numVPorts * m_numHPorts; +} + +size_t +UniformPlanarArray::GetVElemsPerPort() const +{ + return m_numRows / m_numVPorts; +} + +size_t +UniformPlanarArray::GetHElemsPerPort() const +{ + return m_numColumns / m_numHPorts; +} + +size_t +UniformPlanarArray::GetNumElemsPerPort() const +{ + // Multiply the number of rows and number of columns belonging to one antenna port. + // This also holds for dual polarization, where each polarization belongs to a separate port. + return GetVElemsPerPort() * GetHElemsPerPort(); +} + +uint16_t +UniformPlanarArray::ArrayIndexFromPortIndex(uint16_t portIndex, uint16_t subElementIndex) const +{ + NS_ASSERT_MSG(portIndex < GetNumPorts(), "Port should be less than total Ports"); + NS_ASSERT(subElementIndex < (GetHElemsPerPort() * GetVElemsPerPort())); + + // In case the array is dual-polarized, change to the index that belongs to the first + // polarization + auto firstPolPortIdx = portIndex; + auto polarizationOffset = 0; + auto arraySize = GetNumHorizontalPorts() * GetNumVerticalPorts(); + if (firstPolPortIdx >= arraySize) + { + firstPolPortIdx = portIndex - arraySize; + polarizationOffset = GetNumColumns() * GetNumRows(); + } + // column-major indexing + auto hPortIdx = firstPolPortIdx / GetNumVerticalPorts(); + auto vPortIdx = firstPolPortIdx % GetNumVerticalPorts(); + auto hElemIdx = (hPortIdx * GetHElemsPerPort()) + (subElementIndex % GetHElemsPerPort()); + auto vElemIdx = (vPortIdx * GetVElemsPerPort()) + (subElementIndex / GetHElemsPerPort()); + return (vElemIdx * GetNumColumns() + hElemIdx + polarizationOffset); +} + +bool +UniformPlanarArray::IsDualPol() const +{ + return m_isDualPolarized; +} + +void +UniformPlanarArray::SetDualPol(bool isDualPol) +{ + m_isDualPolarized = isDualPol; + if (isDualPol) + { + m_cosPolSlant[1] = cos(m_polSlant - M_PI / 2); + m_sinPolSlant[1] = sin(m_polSlant - M_PI / 2); + } +} + +double +UniformPlanarArray::GetPolSlant() const +{ + return m_polSlant; +} + +uint8_t +UniformPlanarArray::GetElemPol(size_t elemIndex) const +{ + NS_ASSERT(elemIndex < GetNumElems()); + return (elemIndex < GetNumRows() * GetNumColumns()) ? 0 : 1; } } /* namespace ns3 */ diff --git a/src/antenna/model/uniform-planar-array.h b/src/antenna/model/uniform-planar-array.h index 82d23c513..8ba5d4547 100644 --- a/src/antenna/model/uniform-planar-array.h +++ b/src/antenna/model/uniform-planar-array.h @@ -31,7 +31,7 @@ namespace ns3 * \brief Class implementing Uniform Planar Array (UPA) model. * * \note the current implementation supports the modeling of antenna arrays - * composed of a single panel and with single (configured) polarization. + * composed of a single panel and with single or dual polarization. */ class UniformPlanarArray : public PhasedArrayModel { @@ -54,13 +54,15 @@ class UniformPlanarArray : public PhasedArrayModel /** * Returns the horizontal and vertical components of the antenna element field - * pattern at the specified direction. Single polarization is considered. + * pattern at the specified direction and for the specified polarization. * \param a the angle indicating the interested direction + * \param polIndex the index of the polarization for which will be retrieved the field + * pattern * \return a pair in which the first element is the horizontal component * of the field pattern and the second element is the vertical * component of the field pattern */ - std::pair GetElementFieldPattern(Angles a) const override; + std::pair GetElementFieldPattern(Angles a, uint8_t polIndex = 0) const override; /** * Returns the location of the antenna element with the specified @@ -72,32 +74,55 @@ class UniformPlanarArray : public PhasedArrayModel * | 3 4 5 * | 0 1 2 * ----------> y + * In case of dual-polarized antennas, the antennas of the first and the second polarization + * are overlapped in space. * * \param index index of the antenna element - * \return the 3D vector that represents the position of the element + * \return the 3D vector that + * represents the position of the element */ Vector GetElementLocation(uint64_t index) const override; /** - * Returns the number of antenna elements + * Check if an antenna array contains dual-polarized elements + * + * \return true if antenna has two polarization otherwise false + */ + bool IsDualPol() const override; + + /** + * Returns polarization angle of first polarization + * \return polarization angle in radians + */ + double GetPolSlant() const override; + + /** + * Returns the number of polarizations, 2 in the case that + * the antenna is dual-polarized, otherwise 1 + * \return + */ + uint8_t GetNumPols() const override; + + /** + * Returns the number of total antenna elements. Note that if the antenna + * is dual-polarized the number of total antenna elements is doubled. * \return the number of antenna elements */ - size_t GetNumberOfElements() const override; + size_t GetNumElems() const override; - private: /** * Set the number of columns of the phased array * This method resets the stored beamforming vector to a ComplexVector * of the correct size, but zero-filled * \param n the number of columns */ - void SetNumColumns(uint32_t n); + void SetNumColumns(uint32_t n) override; /** * Get the number of columns of the phased array * \return the number of columns */ - uint32_t GetNumColumns() const; + uint32_t GetNumColumns() const override; /** * Set the number of rows of the phased array @@ -105,13 +130,69 @@ class UniformPlanarArray : public PhasedArrayModel * of the correct size, but zero-filled * \param n the number of rows */ - void SetNumRows(uint32_t n); + void SetNumRows(uint32_t n) override; /** * Get the number of rows of the phased array * \return the number of rows */ - uint32_t GetNumRows() const; + uint32_t GetNumRows() const override; + + /** + * Set the number of vertical antenna ports + * \param nPorts The number of vertical ports to be configured + */ + void SetNumVerticalPorts(uint16_t nPorts) override; + + /** + * Set the number of horizontal antenna ports + * \param nPorts + */ + void SetNumHorizontalPorts(uint16_t nPorts) override; + + /** + * Get the number of vertical antenna ports + * \return the number of vertical antenna ports + */ + uint16_t GetNumVerticalPorts() const override; + + /** + * Get the number of horizontal antenna ports + * \return the number of horizontal antenna ports + */ + uint16_t GetNumHorizontalPorts() const override; + + /** + * Get the total number of antenna ports + * \return the number of antenna ports + */ + uint16_t GetNumPorts() const override; + + /** + * Get the number of vertical elements belonging to each port + * \return the number of vertical elements belonging of each port + */ + size_t GetVElemsPerPort() const override; + + /** + * Get the number of horizontal elements belonging to each port + * \return the number of horizontal elements belonging to each port + */ + size_t GetHElemsPerPort() const override; + + /** + * Get the total number of elements belonging to each port + * \return the number of elements per port + */ + size_t GetNumElemsPerPort() const override; + + /** + * Maps element within a port to an index of element within the antenna array + * \param portIndex the port index + * \param subElementIndex the element index within the port + * \return the element index in the antenna array + */ + uint16_t ArrayIndexFromPortIndex(uint16_t portIndex, uint16_t subElementIndex) const override; /** * \brief Set the bearing angle @@ -165,19 +246,37 @@ class UniformPlanarArray : public PhasedArrayModel */ double GetAntennaVerticalSpacing() const; + /** + * Set the polarization + * \param isDualPol whether to set the antenna array to be dual-polarized, + * if true, antenna will be dual-polarized + */ + void SetDualPol(bool isDualPol); + + /** + * Returns the index of polarization to which belongs the antenna element with a specific index + * \param elemIndex the antenna element index + * \return the polarization index + */ + uint8_t GetElemPol(size_t elemIndex) const override; + + private: uint32_t m_numColumns{1}; //!< number of columns uint32_t m_numRows{1}; //!< number of rows double m_disV{0.5}; //!< antenna spacing in the vertical direction in multiples of wave length double m_disH{0.5}; //!< antenna spacing in the horizontal direction in multiples of wave length - double m_alpha{0.0}; //!< the bearing angle in radians - double m_cosAlpha{1.0}; //!< the cosine of alpha - double m_sinAlpha{0.0}; //!< the sine of alpha - double m_beta{0.0}; //!< the downtilt angle in radians - double m_cosBeta{1.0}; //!< the cosine of Beta - double m_sinBeta{0.0}; //!< the sine of Beta - double m_polSlant{0.0}; //!< the polarization slant angle in radians - double m_cosPolSlant{1.0}; //!< the cosine of polarization slant angle - double m_sinPolSlant{0.0}; //!< the sine polarization slant angle + double m_alpha{0.0}; //!< the bearing angle in radians + double m_cosAlpha{1.0}; //!< the cosine of alpha + double m_sinAlpha{0.0}; //!< the sine of alpha + double m_beta{0.0}; //!< the downtilt angle in radians + double m_cosBeta{1.0}; //!< the cosine of Beta + double m_sinBeta{0.0}; //!< the sine of Beta + double m_polSlant{0.0}; //!< the polarization slant angle in radians + bool m_isDualPolarized{false}; //!< if true antenna elements are dual-polarized + uint16_t m_numVPorts{1}; //!< Number of vertical ports + uint16_t m_numHPorts{1}; //!< Number of horizontal ports + std::vector m_cosPolSlant{1.0, 0.0}; //!< the cosine of polarization slant angle + std::vector m_sinPolSlant{0.0, -1.0}; //!< the sine polarization slant angle }; } /* namespace ns3 */ diff --git a/src/antenna/test/test-cosine-antenna.cc b/src/antenna/test/test-cosine-antenna.cc index feabf24b4..014662aff 100644 --- a/src/antenna/test/test-cosine-antenna.cc +++ b/src/antenna/test/test-cosine-antenna.cc @@ -721,7 +721,7 @@ CosineAntennaModelTestSuite::CosineAntennaModelTestSuite() -7, EQUAL), TestCase::QUICK); -}; +} /// Static variable for test initialization static CosineAntennaModelTestSuite g_staticCosineAntennaModelTestSuiteInstance; diff --git a/src/antenna/test/test-degrees-radians.cc b/src/antenna/test/test-degrees-radians.cc index 083d0c691..6643f3ffe 100644 --- a/src/antenna/test/test-degrees-radians.cc +++ b/src/antenna/test/test-degrees-radians.cc @@ -155,7 +155,7 @@ DegreesRadiansTestSuite::DegreesRadiansTestSuite() AddTestCase(new RadiansToDegreesTestCase(M_PI + M_PI, 360), TestCase::QUICK); AddTestCase(new RadiansToDegreesTestCase(-M_PI_2, -90), TestCase::QUICK); AddTestCase(new RadiansToDegreesTestCase(4.5 * M_PI, 810), TestCase::QUICK); -}; +} /// Static variable for test initialization static DegreesRadiansTestSuite g_staticDegreesRadiansTestSuiteInstance; diff --git a/src/antenna/test/test-isotropic-antenna.cc b/src/antenna/test/test-isotropic-antenna.cc index 5dd45198a..1c4ba29fc 100644 --- a/src/antenna/test/test-isotropic-antenna.cc +++ b/src/antenna/test/test-isotropic-antenna.cc @@ -105,7 +105,7 @@ IsotropicAntennaModelTestSuite::IsotropicAntennaModelTestSuite() AddTestCase(new IsotropicAntennaModelTestCase(Angles(M_PI_2, 0), 0.0), TestCase::QUICK); AddTestCase(new IsotropicAntennaModelTestCase(Angles(M_PI_2, M_PI), 0.0), TestCase::QUICK); AddTestCase(new IsotropicAntennaModelTestCase(Angles(M_PI_2, M_PI_2), 0.0), TestCase::QUICK); -}; +} /// Static variable for test initialization static IsotropicAntennaModelTestSuite g_staticIsotropicAntennaModelTestSuiteInstance; diff --git a/src/antenna/test/test-parabolic-antenna.cc b/src/antenna/test/test-parabolic-antenna.cc index eddf0de61..b04347188 100644 --- a/src/antenna/test/test-parabolic-antenna.cc +++ b/src/antenna/test/test-parabolic-antenna.cc @@ -589,7 +589,7 @@ ParabolicAntennaModelTestSuite::ParabolicAntennaModelTestSuite() -3, EQUAL), TestCase::QUICK); -}; +} /// Static variable for test initialization static ParabolicAntennaModelTestSuite g_staticParabolicAntennaModelTestSuiteInstance; diff --git a/src/antenna/test/test-uniform-planar-array.cc b/src/antenna/test/test-uniform-planar-array.cc index 22601057a..a47135061 100644 --- a/src/antenna/test/test-uniform-planar-array.cc +++ b/src/antenna/test/test-uniform-planar-array.cc @@ -153,11 +153,9 @@ UniformPlanarArrayTestCase::ComputeGain(Ptr a) { // compute gain PhasedArrayModel::ComplexVector sv = a->GetSteeringVector(m_direction); - NS_TEST_EXPECT_MSG_EQ(sv.GetSize(), a->GetNumberOfElements(), "steering vector of wrong size"); + NS_TEST_EXPECT_MSG_EQ(sv.GetSize(), a->GetNumElems(), "steering vector of wrong size"); PhasedArrayModel::ComplexVector bf = a->GetBeamformingVector(m_direction); - NS_TEST_EXPECT_MSG_EQ(bf.GetSize(), - a->GetNumberOfElements(), - "beamforming vector of wrong size"); + NS_TEST_EXPECT_MSG_EQ(bf.GetSize(), a->GetNumElems(), "beamforming vector of wrong size"); std::pair fp = a->GetElementFieldPattern(m_direction); // scalar product dot (sv, bf) diff --git a/src/aodv/CMakeLists.txt b/src/aodv/CMakeLists.txt index 5839e6a7c..eebb269b5 100644 --- a/src/aodv/CMakeLists.txt +++ b/src/aodv/CMakeLists.txt @@ -18,8 +18,10 @@ build_lib( model/aodv-routing-protocol.h model/aodv-rqueue.h model/aodv-rtable.h - LIBRARIES_TO_LINK ${libinternet} - ${libwifi} + LIBRARIES_TO_LINK + ${libapplications} + ${libinternet-apps} + ${libwifi} TEST_SOURCES test/aodv-id-cache-test-suite.cc test/aodv-regression.cc diff --git a/src/aodv/model/aodv-packet.h b/src/aodv/model/aodv-packet.h index 47ad243cf..029012207 100644 --- a/src/aodv/model/aodv-packet.h +++ b/src/aodv/model/aodv-packet.h @@ -485,7 +485,7 @@ class RrepHeader : public Header */ void SetPrefixSize(uint8_t sz); /** - * \brief Set the pefix size + * \brief Set the prefix size * \return the prefix size */ uint8_t GetPrefixSize() const; diff --git a/src/aodv/model/aodv-routing-protocol.cc b/src/aodv/model/aodv-routing-protocol.cc index b0352e413..158dccde1 100644 --- a/src/aodv/model/aodv-routing-protocol.cc +++ b/src/aodv/model/aodv-routing-protocol.cc @@ -1379,7 +1379,7 @@ RoutingProtocol::RecvRequest(Ptr p, Ipv4Address receiver, Ipv4Address sr /*iface=*/m_ipv4->GetAddress(m_ipv4->GetInterfaceForAddress(receiver), 0), /*hops=*/hop, /*nextHop=*/src, - /*lifetime=*/Time((2 * m_netTraversalTime - 2 * hop * m_nodeTraversalTime))); + /*lifetime=*/Time(2 * m_netTraversalTime - 2 * hop * m_nodeTraversalTime)); m_routingTable.AddRoute(newEntry); } else diff --git a/src/aodv/model/aodv-rqueue.cc b/src/aodv/model/aodv-rqueue.cc index b45625613..aab6ab911 100644 --- a/src/aodv/model/aodv-rqueue.cc +++ b/src/aodv/model/aodv-rqueue.cc @@ -121,14 +121,13 @@ RequestQueue::Find(Ipv4Address dst) */ struct IsExpired { - bool /** * Check if the entry is expired * * \param e QueueEntry entry * \return true if expired, false otherwise */ - operator()(const QueueEntry& e) const + bool operator()(const QueueEntry& e) const { return (e.GetExpireTime() < Seconds(0)); } diff --git a/src/aodv/test/bug-772.cc b/src/aodv/test/bug-772.cc index 0719448b8..cd41059d9 100644 --- a/src/aodv/test/bug-772.cc +++ b/src/aodv/test/bug-772.cc @@ -37,7 +37,6 @@ #include "ns3/simulator.h" #include "ns3/string.h" #include "ns3/uinteger.h" -#include "ns3/v4ping-helper.h" #include "ns3/yans-wifi-helper.h" #include diff --git a/src/aodv/test/loopback.cc b/src/aodv/test/loopback.cc index 57973ff0a..b4beff597 100644 --- a/src/aodv/test/loopback.cc +++ b/src/aodv/test/loopback.cc @@ -36,7 +36,6 @@ #include "ns3/udp-echo-helper.h" #include "ns3/udp-socket-factory.h" #include "ns3/uinteger.h" -#include "ns3/v4ping.h" #include "ns3/yans-wifi-helper.h" #include diff --git a/src/applications/CMakeLists.txt b/src/applications/CMakeLists.txt index 77b0993ad..21ba0aa6d 100644 --- a/src/applications/CMakeLists.txt +++ b/src/applications/CMakeLists.txt @@ -49,7 +49,6 @@ build_lib( model/udp-server.h model/udp-trace-client.h LIBRARIES_TO_LINK ${libinternet} - ${libstats} TEST_SOURCES test/three-gpp-http-client-server-test.cc test/bulk-send-application-test-suite.cc diff --git a/src/applications/helper/bulk-send-helper.h b/src/applications/helper/bulk-send-helper.h index af714b0e0..803b11d91 100644 --- a/src/applications/helper/bulk-send-helper.h +++ b/src/applications/helper/bulk-send-helper.h @@ -49,7 +49,7 @@ class BulkSendHelper * \param protocol the name of the protocol to use to send traffic * by the applications. This string identifies the socket * factory type used to create sockets for the applications. - * A typical value would be ns3::UdpSocketFactory. + * A typical value would be ns3::TcpSocketFactory. * \param address the address of the remote node to send traffic * to. */ diff --git a/src/applications/model/udp-trace-client.h b/src/applications/model/udp-trace-client.h index 9dd8498e7..c04f13828 100644 --- a/src/applications/model/udp-trace-client.h +++ b/src/applications/model/udp-trace-client.h @@ -41,7 +41,7 @@ class Packet; * * Sends UDP packets based on a trace file of a MPEG4 stream. * Trace files can be downloaded from: - * http://trace.eas.asu.edu/mpeg4/index.html + * https://web.archive.org/web/20210113211420/http://trace.eas.asu.edu/mpeg4/index.html * (the 2 first lines of the file should be removed) A valid trace file is a file with 4 columns: * \li -1- the first one represents the frame index * \li -2- the second one indicates the type of the frame: I, P or B diff --git a/src/applications/test/udp-client-server-test.cc b/src/applications/test/udp-client-server-test.cc index 33509284a..36fecb721 100644 --- a/src/applications/test/udp-client-server-test.cc +++ b/src/applications/test/udp-client-server-test.cc @@ -31,6 +31,7 @@ #include "ns3/test.h" #include "ns3/udp-client-server-helper.h" #include "ns3/udp-echo-helper.h" +#include "ns3/udp-server.h" #include "ns3/uinteger.h" #include diff --git a/src/bridge/CMakeLists.txt b/src/bridge/CMakeLists.txt index 4436724ee..1ad725c01 100644 --- a/src/bridge/CMakeLists.txt +++ b/src/bridge/CMakeLists.txt @@ -9,5 +9,4 @@ build_lib( model/bridge-channel.h model/bridge-net-device.h LIBRARIES_TO_LINK ${libnetwork} - TEST_SOURCES ${test_sources} ) diff --git a/src/bridge/examples/csma-bridge.py b/src/bridge/examples/csma-bridge.py index 293a02aad..73294e672 100644 --- a/src/bridge/examples/csma-bridge.py +++ b/src/bridge/examples/csma-bridge.py @@ -1,17 +1,17 @@ -# /* -# * 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 -# */ +# +# 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 +# # Network topology # @@ -32,12 +32,18 @@ # \ingroup bridge # Bridge example connecting two broadcast domains. - -from ns import ns +## Import ns-3 +try: + from ns import ns +except ModuleNotFoundError: + raise SystemExit( + "Error: ns3 Python module not found;" + " Python bindings may not be enabled" + " or your PYTHONPATH might not be properly configured" + ) def main(argv): - # # Allow the user to override any of the defaults and the above Bind() at # run-time, via command-line arguments @@ -48,14 +54,14 @@ def main(argv): # # Explicitly create the nodes required by the topology(shown above). # - #print "Create nodes." + # print "Create nodes." terminals = ns.network.NodeContainer() terminals.Create(4) csmaSwitch = ns.network.NodeContainer() csmaSwitch.Create(1) - #print "Build Topology" + # print "Build Topology" csma = ns.csma.CsmaHelper() csma.SetChannelAttribute("DataRate", ns.network.DataRateValue(ns.network.DataRate(5000000))) csma.SetChannelAttribute("Delay", ns.core.TimeValue(ns.core.MilliSeconds(2))) @@ -66,7 +72,9 @@ def main(argv): switchDevices = ns.network.NetDeviceContainer() for i in range(4): - link = csma.Install(ns.network.NodeContainer(ns.network.NodeContainer(terminals.Get(i)), csmaSwitch)) + link = csma.Install( + ns.network.NodeContainer(ns.network.NodeContainer(terminals.Get(i)), csmaSwitch) + ) terminalDevices.Add(link.Get(0)) switchDevices.Add(link.Get(1)) @@ -84,7 +92,7 @@ def main(argv): # We've got the "hardware" in place. Now we need to add IP addresses. # - #print "Assign IP Addresses." + # print "Assign IP Addresses." ipv4 = ns.internet.Ipv4AddressHelper() ipv4.SetBase(ns.network.Ipv4Address("10.1.1.0"), ns.network.Ipv4Mask("255.255.255.0")) ipv4.Assign(terminalDevices) @@ -92,12 +100,12 @@ def main(argv): # # Create an OnOff application to send UDP datagrams from node zero to node 1. # - #print "Create Applications." - port = 9 # Discard port(RFC 863) + # print "Create Applications." + port = 9 # Discard port(RFC 863) inet_sock_address = ns.network.InetSocketAddress(ns.network.Ipv4Address("10.1.1.2"), port) onoff = ns.applications.OnOffHelper("ns3::UdpSocketFactory", inet_sock_address.ConvertTo()) - onoff.SetConstantRate (ns.network.DataRate ("500kb/s")) + onoff.SetConstantRate(ns.network.DataRate("500kb/s")) app = onoff.Install(ns.network.NodeContainer(terminals.Get(0))) # Start the application @@ -114,8 +122,7 @@ def main(argv): # Create a similar flow from n3 to n0, starting at time 1.1 seconds # inet_address = ns.network.InetSocketAddress(ns.network.Ipv4Address("10.1.1.1"), port) - onoff.SetAttribute("Remote", - ns.network.AddressValue(inet_address.ConvertTo())) + onoff.SetAttribute("Remote", ns.network.AddressValue(inet_address.ConvertTo())) app = onoff.Install(ns.network.NodeContainer(terminals.Get(3))) app.Start(ns.core.Seconds(1.1)) app.Stop(ns.core.Seconds(10.0)) @@ -127,9 +134,9 @@ def main(argv): # Configure tracing of all enqueue, dequeue, and NetDevice receive events. # Trace output will be sent to the file "csma-bridge.tr" # - #print "Configure Tracing." - #ascii = ns.network.AsciiTraceHelper(); - #csma.EnableAsciiAll(ascii.CreateFileStream ("csma-bridge.tr")); + # print "Configure Tracing." + # ascii = ns.network.AsciiTraceHelper(); + # csma.EnableAsciiAll(ascii.CreateFileStream ("csma-bridge.tr")); # # Also configure some tcpdump traces; each interface will be traced. @@ -143,14 +150,13 @@ def main(argv): # # Now, do the actual simulation. # - #print "Run Simulation." + # print "Run Simulation." ns.core.Simulator.Run() ns.core.Simulator.Destroy() - #print "Done." + # print "Done." - -if __name__ == '__main__': +if __name__ == "__main__": import sys - main(sys.argv) + main(sys.argv) diff --git a/src/brite/CMakeLists.txt b/src/brite/CMakeLists.txt index 99c7be210..1c79e5a27 100644 --- a/src/brite/CMakeLists.txt +++ b/src/brite/CMakeLists.txt @@ -14,6 +14,7 @@ find_external_library( HEADER_NAME Brite.h LIBRARY_NAME brite SEARCH_PATHS ${NS3_WITH_BRITE} + OUTPUT_VARIABLE "NS3_BRITE_REASON" ) if((NOT @@ -49,9 +50,7 @@ build_lib( SOURCE_FILES helper/brite-topology-helper.cc HEADER_FILES helper/brite-topology-helper.h LIBRARIES_TO_LINK - ${libnetwork} - ${libcore} - ${libinternet} + ${libapplications} ${libpoint-to-point} ${brite_LIBRARIES} TEST_SOURCES test/brite-test-topology.cc diff --git a/src/brite/examples/brite-generic-example.py b/src/brite/examples/brite-generic-example.py index 24e45b963..d5647e30d 100644 --- a/src/brite/examples/brite-generic-example.py +++ b/src/brite/examples/brite-generic-example.py @@ -18,7 +18,14 @@ # Modified by: Gabriel Ferreira # -from ns import ns +try: + from ns import ns +except ModuleNotFoundError: + raise SystemExit( + "Error: ns3 Python module not found;" + " Python bindings may not be enabled" + " or your PYTHONPATH might not be properly configured" + ) ns.LogComponentEnable("BriteTopologyHelper", ns.LOG_LEVEL_ALL) @@ -88,7 +95,7 @@ serverApps.Stop(ns.Seconds(5.0)) echoClient = ns.UdpEchoClientHelper(serverInterfaces.GetAddress(0).ConvertTo(), 9) echoClient.SetAttribute("MaxPackets", ns.UintegerValue(1)) -echoClient.SetAttribute("Interval", ns.TimeValue(ns.Seconds(1.))) +echoClient.SetAttribute("Interval", ns.TimeValue(ns.Seconds(1.0))) echoClient.SetAttribute("PacketSize", ns.UintegerValue(1024)) clientApps = echoClient.Install(client.Get(0)) diff --git a/src/brite/helper/brite-topology-helper.h b/src/brite/helper/brite-topology-helper.h index 52aa1f7c4..08a60e0f4 100644 --- a/src/brite/helper/brite-topology-helper.h +++ b/src/brite/helper/brite-topology-helper.h @@ -32,7 +32,7 @@ // here we just need a forward declaration. namespace brite { -struct Topology; +class Topology; }; namespace ns3 diff --git a/src/buildings/CMakeLists.txt b/src/buildings/CMakeLists.txt index 104ddb5fb..ecf2c8230 100644 --- a/src/buildings/CMakeLists.txt +++ b/src/buildings/CMakeLists.txt @@ -30,8 +30,7 @@ build_lib( model/oh-buildings-propagation-loss-model.h model/random-walk-2d-outdoor-mobility-model.h model/three-gpp-v2v-channel-condition-model.h - LIBRARIES_TO_LINK ${libmobility} - ${libpropagation} + LIBRARIES_TO_LINK ${libpropagation} TEST_SOURCES test/buildings-channel-condition-model-test.cc test/buildings-helper-test.cc diff --git a/src/buildings/doc/source/conf.py b/src/buildings/doc/source/conf.py index 3e9955680..f6ff4466d 100644 --- a/src/buildings/doc/source/conf.py +++ b/src/buildings/doc/source/conf.py @@ -11,206 +11,209 @@ # All configuration values have a default; values that are commented out # serve to show the default. -import sys, os +import os +import sys # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('.')) +# sys.path.insert(0, os.path.abspath('.')) # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' +# needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.imgmath', - 'sphinxcontrib.seqdiag'] +extensions = ["sphinx.ext.imgmath", "sphinxcontrib.seqdiag"] # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # The suffix of source filenames. -source_suffix = '.rst' +source_suffix = ".rst" # The encoding of source files. -#source_encoding = 'utf-8-sig' +# source_encoding = 'utf-8-sig' # The master toctree document. -master_doc = 'buildings' +master_doc = "buildings" # General information about the project. -project = u'LENA' -copyright = u'2011-2012, CTTC' +project = "LENA" +copyright = "2011-2012, CTTC" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. -version = 'M2' +version = "M2" # The full version, including alpha/beta/rc tags. -release = 'M2' +release = "M2" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. -#language = None +# language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: -#today = '' +# today = '' # Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' +# today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = [] # The reST default role (used for this markup: `text`) to use for all documents. -#default_role = None +# default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True +# add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). -#add_module_names = True +# add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. -#show_authors = False +# show_authors = False # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +pygments_style = "sphinx" # A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] +# modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = 'default' +html_theme = "default" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. -#html_theme_options = {} +# html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] +# html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". -#html_title = None +# html_title = None # A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None +# html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. -#html_logo = None +# html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. -#html_favicon = None +# html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -#html_static_path = ['_static'] +# html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' +# html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. -#html_use_smartypants = True +# html_use_smartypants = True # Custom sidebar templates, maps document names to template names. -#html_sidebars = {} +# html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. -#html_additional_pages = {} +# html_additional_pages = {} # If false, no module index is generated. -#html_domain_indices = True +# html_domain_indices = True # If false, no index is generated. -#html_use_index = True +# html_use_index = True # If true, the index is split into individual pages for each letter. -#html_split_index = False +# html_split_index = False # If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True +# html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True +# html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True +# html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. -#html_use_opensearch = '' +# html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None +# html_file_suffix = None # Output file base name for HTML help builder. -#htmlhelp_basename = 'ns-3doc' +# htmlhelp_basename = 'ns-3doc' # -- Options for LaTeX output -------------------------------------------------- # The paper size ('letter' or 'a4'). -#latex_paper_size = 'letter' +# latex_paper_size = 'letter' # The font size ('10pt', '11pt' or '12pt'). -#latex_font_size = '10pt' +# latex_font_size = '10pt' # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ - ('buildings', 'buildings.tex', u'Buildings Module Documentation', u'Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)', 'manual'), + ( + "buildings", + "buildings.tex", + "Buildings Module Documentation", + "Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)", + "manual", + ), ] # The name of an image file (relative to this directory) to place at the top of # the title page. -#latex_logo = None +# latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. -#latex_use_parts = False +# latex_use_parts = False # If true, show page references after internal links. -#latex_show_pagerefs = False +# latex_show_pagerefs = False # If true, show URL addresses after external links. -#latex_show_urls = False +# latex_show_urls = False # Additional stuff for the LaTeX preamble. -#latex_preamble = '' +# latex_preamble = '' # Documents to append as an appendix to all manuals. -#latex_appendices = [] +# latex_appendices = [] # If false, no module index is generated. -#latex_domain_indices = True +# latex_domain_indices = True # -- Options for manual page output -------------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [ - ('index', 'ns-3-model-library', u'ns-3 Model Library', - [u'ns-3 project'], 1) -] +man_pages = [("index", "ns-3-model-library", "ns-3 Model Library", ["ns-3 project"], 1)] diff --git a/src/buildings/helper/building-allocator.cc b/src/buildings/helper/building-allocator.cc index d671bac35..774004357 100644 --- a/src/buildings/helper/building-allocator.cc +++ b/src/buildings/helper/building-allocator.cc @@ -99,7 +99,8 @@ GridBuildingAllocator::GetTypeId() .AddAttribute("LayoutType", "The type of layout.", EnumValue(GridPositionAllocator::ROW_FIRST), - MakeEnumAccessor(&GridBuildingAllocator::m_layoutType), + MakeEnumAccessor( + &GridBuildingAllocator::m_layoutType), MakeEnumChecker(GridPositionAllocator::ROW_FIRST, "RowFirst", GridPositionAllocator::COLUMN_FIRST, diff --git a/src/buildings/model/building.cc b/src/buildings/model/building.cc index ead9dcd9d..192b262da 100644 --- a/src/buildings/model/building.cc +++ b/src/buildings/model/building.cc @@ -73,7 +73,8 @@ Building::GetTypeId() .AddAttribute("Type", "The type of building", EnumValue(Building::Residential), - MakeEnumAccessor(&Building::GetBuildingType, &Building::SetBuildingType), + MakeEnumAccessor(&Building::GetBuildingType, + &Building::SetBuildingType), MakeEnumChecker(Building::Residential, "Residential", Building::Office, @@ -83,7 +84,8 @@ Building::GetTypeId() .AddAttribute("ExternalWallsType", "The type of material of which the external walls are made", EnumValue(Building::ConcreteWithWindows), - MakeEnumAccessor(&Building::GetExtWallsType, &Building::SetExtWallsType), + MakeEnumAccessor(&Building::GetExtWallsType, + &Building::SetExtWallsType), MakeEnumChecker(Building::Wood, "Wood", Building::ConcreteWithWindows, diff --git a/src/buildings/model/buildings-propagation-loss-model.cc b/src/buildings/model/buildings-propagation-loss-model.cc index 9c8878a7c..37d15bdb6 100644 --- a/src/buildings/model/buildings-propagation-loss-model.cc +++ b/src/buildings/model/buildings-propagation-loss-model.cc @@ -54,7 +54,7 @@ BuildingsPropagationLossModel::ShadowingLoss::ShadowingLoss(double shadowingValu double BuildingsPropagationLossModel::ShadowingLoss::GetLoss() const { - return (m_shadowingValue); + return m_shadowingValue; } Ptr @@ -130,7 +130,7 @@ BuildingsPropagationLossModel::ExternalWallLoss(Ptr a) con { loss = 12; } - return (loss); + return loss; } double @@ -140,7 +140,7 @@ BuildingsPropagationLossModel::HeightLoss(Ptr node) const int nfloors = node->GetFloorNumber() - 1; loss = -2 * (nfloors); - return (loss); + return loss; } double @@ -166,7 +166,7 @@ BuildingsPropagationLossModel::GetShadowing(Ptr a, Ptrsecond.find(b); if (bit != ait->second.end()) { - return (bit->second.GetLoss()); + return bit->second.GetLoss(); } else { @@ -175,7 +175,7 @@ BuildingsPropagationLossModel::GetShadowing(Ptr a, PtrGetValue(0.0, (sigma * sigma)); ait->second[b] = ShadowingLoss(shadowingValue, b); - return (ait->second[b].GetLoss()); + return ait->second[b].GetLoss(); } } else @@ -185,7 +185,7 @@ BuildingsPropagationLossModel::GetShadowing(Ptr a, PtrGetValue(0.0, (sigma * sigma)); m_shadowingLossMap[a][b] = ShadowingLoss(shadowingValue, b); - return (m_shadowingLossMap[a][b].GetLoss()); + return m_shadowingLossMap[a][b].GetLoss(); } } @@ -200,24 +200,24 @@ BuildingsPropagationLossModel::EvaluateSigma(Ptr a, { if (!isBIndoor) // b is outdoor { - return (m_shadowingSigmaOutdoor); + return m_shadowingSigmaOutdoor; } else { double sigma = std::sqrt((m_shadowingSigmaOutdoor * m_shadowingSigmaOutdoor) + (m_shadowingSigmaExtWalls * m_shadowingSigmaExtWalls)); - return (sigma); + return sigma; } } else if (isBIndoor) // b is indoor { - return (m_shadowingSigmaIndoor); + return m_shadowingSigmaIndoor; } else { double sigma = std::sqrt((m_shadowingSigmaOutdoor * m_shadowingSigmaOutdoor) + (m_shadowingSigmaExtWalls * m_shadowingSigmaExtWalls)); - return (sigma); + return sigma; } } diff --git a/src/buildings/model/hybrid-buildings-propagation-loss-model.cc b/src/buildings/model/hybrid-buildings-propagation-loss-model.cc index 9919d3933..9cf60b515 100644 --- a/src/buildings/model/hybrid-buildings-propagation-loss-model.cc +++ b/src/buildings/model/hybrid-buildings-propagation-loss-model.cc @@ -83,7 +83,8 @@ HybridBuildingsPropagationLossModel::GetTypeId() .AddAttribute("Environment", "Environment Scenario", EnumValue(UrbanEnvironment), - MakeEnumAccessor(&HybridBuildingsPropagationLossModel::SetEnvironment), + MakeEnumAccessor( + &HybridBuildingsPropagationLossModel::SetEnvironment), MakeEnumChecker(UrbanEnvironment, "Urban", SubUrbanEnvironment, @@ -95,7 +96,7 @@ HybridBuildingsPropagationLossModel::GetTypeId() "CitySize", "Dimension of the city", EnumValue(LargeCity), - MakeEnumAccessor(&HybridBuildingsPropagationLossModel::SetCitySize), + MakeEnumAccessor(&HybridBuildingsPropagationLossModel::SetCitySize), MakeEnumChecker(SmallCity, "Small", MediumCity, "Medium", LargeCity, "Large")) .AddAttribute( @@ -278,11 +279,11 @@ HybridBuildingsPropagationLossModel::ItuR1411(Ptr a, PtrGetDistanceFrom(b) < m_itu1411NlosThreshold) { - return (m_ituR1411Los->GetLoss(a, b)); + return m_ituR1411Los->GetLoss(a, b); } else { - return (m_ituR1411NlosOverRooftop->GetLoss(a, b)); + return m_ituR1411NlosOverRooftop->GetLoss(a, b); } } diff --git a/src/buildings/model/mobility-building-info.cc b/src/buildings/model/mobility-building-info.cc index c6b5f5c08..f51c68af9 100644 --- a/src/buildings/model/mobility-building-info.cc +++ b/src/buildings/model/mobility-building-info.cc @@ -139,28 +139,28 @@ uint8_t MobilityBuildingInfo::GetFloorNumber() { NS_LOG_FUNCTION(this); - return (m_nFloor); + return m_nFloor; } uint8_t MobilityBuildingInfo::GetRoomNumberX() { NS_LOG_FUNCTION(this); - return (m_roomX); + return m_roomX; } uint8_t MobilityBuildingInfo::GetRoomNumberY() { NS_LOG_FUNCTION(this); - return (m_roomY); + return m_roomY; } Ptr MobilityBuildingInfo::GetBuilding() { NS_LOG_FUNCTION(this); - return (m_myBuilding); + return m_myBuilding; } void diff --git a/src/buildings/model/random-walk-2d-outdoor-mobility-model.cc b/src/buildings/model/random-walk-2d-outdoor-mobility-model.cc index 6a2420653..23e13b832 100644 --- a/src/buildings/model/random-walk-2d-outdoor-mobility-model.cc +++ b/src/buildings/model/random-walk-2d-outdoor-mobility-model.cc @@ -68,7 +68,7 @@ RandomWalk2dOutdoorMobilityModel::GetTypeId() "The mode indicates the condition used to " "change the current speed and direction", EnumValue(RandomWalk2dOutdoorMobilityModel::MODE_DISTANCE), - MakeEnumAccessor(&RandomWalk2dOutdoorMobilityModel::m_mode), + MakeEnumAccessor(&RandomWalk2dOutdoorMobilityModel::m_mode), MakeEnumChecker(RandomWalk2dOutdoorMobilityModel::MODE_DISTANCE, "Distance", RandomWalk2dOutdoorMobilityModel::MODE_TIME, diff --git a/src/click/CMakeLists.txt b/src/click/CMakeLists.txt index 72cd22495..1c4e8e9a4 100644 --- a/src/click/CMakeLists.txt +++ b/src/click/CMakeLists.txt @@ -17,6 +17,7 @@ find_external_library( PATH_SUFFIXES userlevel ns SEARCH_PATHS ${NS3_WITH_CLICK} + OUTPUT_VARIABLE "NS3_CLICK_REASON" ) if((NOT @@ -58,10 +59,7 @@ build_lib( helper/click-internet-stack-helper.h model/ipv4-click-routing.h model/ipv4-l3-click-protocol.h - LIBRARIES_TO_LINK - ${libcore} - ${libnetwork} - ${libinternet} - ${click_LIBRARIES} + LIBRARIES_TO_LINK ${libinternet} + ${click_LIBRARIES} TEST_SOURCES test/ipv4-click-routing-test.cc ) diff --git a/src/click/examples/nsclick-simple-lan.py b/src/click/examples/nsclick-simple-lan.py index 3a32e62f1..58760374c 100644 --- a/src/click/examples/nsclick-simple-lan.py +++ b/src/click/examples/nsclick-simple-lan.py @@ -18,7 +18,14 @@ import os.path -from ns import ns +try: + from ns import ns +except ModuleNotFoundError: + raise SystemExit( + "Error: ns3 Python module not found;" + " Python bindings may not be enabled" + " or your PYTHONPATH might not be properly configured" + ) ns.LogComponentEnable("Ipv4ClickRouting", ns.LOG_LEVEL_ALL) ns.LogComponentEnable("Ipv4L3ClickProtocol", ns.LOG_LEVEL_ALL) @@ -40,8 +47,9 @@ internet.Install(csmaNodes.Get(1)) # Install Click on node A clickinternet = ns.ClickInternetStackHelper() -clickinternet.SetClickFile(csmaNodes.Get(0), - clickConfigFolder + "/nsclick-lan-single-interface.click") +clickinternet.SetClickFile( + csmaNodes.Get(0), clickConfigFolder + "/nsclick-lan-single-interface.click" +) clickinternet.SetRoutingTableElement(csmaNodes.Get(0), "rt") clickinternet.Install(csmaNodes.Get(0)) diff --git a/src/click/model/ipv4-l3-click-protocol.cc b/src/click/model/ipv4-l3-click-protocol.cc index 7f050c1b8..15c1e7848 100644 --- a/src/click/model/ipv4-l3-click-protocol.cc +++ b/src/click/model/ipv4-l3-click-protocol.cc @@ -238,7 +238,7 @@ Ipv4L3ClickProtocol::IsDestinationAddress(Ipv4Address address, uint32_t iif) con return true; } - if (GetWeakEsModel()) // Check other interfaces + if (!GetStrongEndSystemModel()) // Check other interfaces { for (uint32_t j = 0; j < GetNInterfaces(); j++) { @@ -287,13 +287,25 @@ Ipv4L3ClickProtocol::GetIpForward() const void Ipv4L3ClickProtocol::SetWeakEsModel(bool model) { - m_weakEsModel = model; + m_strongEndSystemModel = !model; } bool Ipv4L3ClickProtocol::GetWeakEsModel() const { - return m_weakEsModel; + return !m_strongEndSystemModel; +} + +void +Ipv4L3ClickProtocol::SetStrongEndSystemModel(bool model) +{ + m_strongEndSystemModel = model; +} + +bool +Ipv4L3ClickProtocol::GetStrongEndSystemModel() const +{ + return m_strongEndSystemModel; } Ptr diff --git a/src/click/model/ipv4-l3-click-protocol.h b/src/click/model/ipv4-l3-click-protocol.h index d90f5403d..2fb06e9cf 100644 --- a/src/click/model/ipv4-l3-click-protocol.h +++ b/src/click/model/ipv4-l3-click-protocol.h @@ -21,6 +21,7 @@ #ifndef IPV4_L3_CLICK_PROTOCOL_H #define IPV4_L3_CLICK_PROTOCOL_H +#include "ns3/deprecated.h" #include "ns3/ipv4-interface.h" #include "ns3/ipv4-routing-protocol.h" #include "ns3/ipv4.h" @@ -266,9 +267,15 @@ class Ipv4L3ClickProtocol : public Ipv4 void SetIpForward(bool forward) override; bool GetIpForward() const override; + + NS_DEPRECATED_3_41("Use SetStrongEndSystemModel instead") void SetWeakEsModel(bool model) override; + NS_DEPRECATED_3_41("Use GetStrongEndSystemModel instead") bool GetWeakEsModel() const override; + void SetStrongEndSystemModel(bool model) override; + bool GetStrongEndSystemModel() const override; + /** * \brief List of IPv4 interfaces. */ @@ -296,7 +303,7 @@ class Ipv4L3ClickProtocol : public Ipv4 Ptr m_routingProtocol; //!< IPv4 routing protocol bool m_ipForward; //!< Whether IP forwarding is enabled - bool m_weakEsModel; //!< Whether to use weak Es model + bool m_strongEndSystemModel; //!< Whether to use Strong End System Model L4List_t m_protocols; //!< List of IPv4 L4 protocols Ipv4InterfaceList m_interfaces; //!< List of interfaces Ipv4InterfaceReverseContainer diff --git a/src/click/test/examples-to-run.py b/src/click/test/examples-to-run.py index 342e58a9f..09d23ea39 100644 --- a/src/click/test/examples-to-run.py +++ b/src/click/test/examples-to-run.py @@ -9,8 +9,16 @@ cpp_examples = [ ("nsclick-simple-lan --clickConfigFolder=../../src/click/examples", "NSCLICK == True", "False"), ("nsclick-raw-wlan --clickConfigFolder=../../src/click/examples", "NSCLICK == True", "False"), - ("nsclick-udp-client-server-csma --clickConfigFolder=../../src/click/examples", "NSCLICK == True", "False"), - ("nsclick-udp-client-server-wifi --clickConfigFolder=../../src/click/examples", "NSCLICK == True", "False"), + ( + "nsclick-udp-client-server-csma --clickConfigFolder=../../src/click/examples", + "NSCLICK == True", + "False", + ), + ( + "nsclick-udp-client-server-wifi --clickConfigFolder=../../src/click/examples", + "NSCLICK == True", + "False", + ), ("nsclick-routing --clickConfigFolder=../../src/click/examples", "NSCLICK == True", "False"), ("nsclick-defines --clickConfigFolder=../../src/click/examples", "NSCLICK == True", "False"), ] diff --git a/src/config-store/CMakeLists.txt b/src/config-store/CMakeLists.txt index b62fba3e3..ec0b6ed94 100644 --- a/src/config-store/CMakeLists.txt +++ b/src/config-store/CMakeLists.txt @@ -1,3 +1,6 @@ +set(gtk3_sources) +set(gtk3_headers) +set(gtk_libraries) if(${GTK3_FOUND}) set(gtk3_sources model/display-functions.cc @@ -19,11 +22,10 @@ if(${GTK3_FOUND}) -Wl,--allow-shlib-undefined ) endif() - if(${GCC}) - add_definitions(-Wno-parentheses) - endif() endif() +set(xml2_sources) +set(xml2_libraries) if(${LIBXML2_FOUND}) set(xml2_sources model/xml-config.cc @@ -49,7 +51,6 @@ build_lib( model/config-store.h LIBRARIES_TO_LINK ${libcore} - ${libnetwork} ${xml2_libraries} ${gtk_libraries} ) diff --git a/src/config-store/model/config-store.cc b/src/config-store/model/config-store.cc index c81f06708..05a2dec35 100644 --- a/src/config-store/model/config-store.cc +++ b/src/config-store/model/config-store.cc @@ -56,7 +56,7 @@ ConfigStore::GetTypeId() .AddAttribute("Mode", "Configuration mode", EnumValue(ConfigStore::NONE), - MakeEnumAccessor(&ConfigStore::SetMode), + MakeEnumAccessor(&ConfigStore::SetMode), MakeEnumChecker(ConfigStore::NONE, "None", ConfigStore::LOAD, @@ -72,7 +72,7 @@ ConfigStore::GetTypeId() "FileFormat", "Type of file format", EnumValue(ConfigStore::RAW_TEXT), - MakeEnumAccessor(&ConfigStore::SetFileFormat), + MakeEnumAccessor(&ConfigStore::SetFileFormat), MakeEnumChecker(ConfigStore::RAW_TEXT, "RawText", ConfigStore::XML, "Xml")) .AddAttribute("SaveDeprecated", "Save DEPRECATED attributes", diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index fb5e1ee1c..2c6e7aff2 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -14,38 +14,12 @@ if(${GSL_FOUND}) endif() # Check for dependencies and add sources accordingly -if(${CMAKE_VERSION} - VERSION_LESS - "3.11.0" +check_include_files( + "boost/units/quantity.hpp;boost/units/systems/si.hpp" + HAVE_BOOST_UNITS + LANGUAGE + CXX ) - check_include_file_cxx( - boost/units/quantity.hpp - HAVE_BOOST_UNITS_QUANTITY - ) - check_include_file_cxx( - boost/units/systems/si.hpp - HAVE_BOOST_UNITS_SI - ) - if(${HAVE_BOOST_UNITS_QUANTITY} - AND ${HAVE_BOOST_UNITS_SI} - ) - set(HAVE_BOOST_UNITS - TRUE - ) - else() - set(HAVE_BOOST_UNITS - FALSE - ) - endif() -else() - # Fast path for CMake >= 3.11 - check_include_files( - "boost/units/quantity.hpp;boost/units/systems/si.hpp" - HAVE_BOOST_UNITS - LANGUAGE - CXX - ) -endif() if(${HAVE_BOOST_UNITS}) add_definitions( @@ -97,6 +71,9 @@ elseif( ) endif() +set(example_as_test_sources) +set(example_as_test_headers) +set(example_as_test_suite) if(${ENABLE_EXAMPLES}) set(example_as_test_sources model/example-as-test.cc @@ -177,7 +154,6 @@ set(source_files model/boolean.cc model/integer.cc model/uinteger.cc - model/enum.cc model/double.cc model/int64x64.cc model/string.cc @@ -306,7 +282,7 @@ set(header_files model/type-name.h model/type-traits.h model/uinteger.h - model/unused.h + model/uniform-random-bit-generator.h model/valgrind.h model/vector.h model/warnings.h diff --git a/src/core/examples/main-random-variable-stream.cc b/src/core/examples/main-random-variable-stream.cc index 96ef3f8e5..ea435936b 100644 --- a/src/core/examples/main-random-variable-stream.cc +++ b/src/core/examples/main-random-variable-stream.cc @@ -555,6 +555,37 @@ main(int argc, char* argv[]) std::cout << "done" << std::endl; } + { + std::cout << "BinomialRandomVariable......." << std::flush; + Gnuplot plot; + plot.SetTitle("BinomialRandomVariable"); + plot.AppendExtra("set yrange [0:10]"); + + auto x = CreateObject(); + x->SetAttribute("Trials", IntegerValue(10)); + x->SetAttribute("Probability", DoubleValue(0.5)); + + plot.AddDataset(Histogram(x, probes, precision, "BinomialRandomVariable n=10 p=0.5")); + + gnuplots.AddPlot(plot); + std::cout << "done" << std::endl; + } + + { + std::cout << "BernoulliRandomVariable......." << std::flush; + Gnuplot plot; + plot.SetTitle("BernoulliRandomVariable"); + plot.AppendExtra("set yrange [0:1]"); + + auto x = CreateObject(); + x->SetAttribute("Probability", DoubleValue(0.5)); + + plot.AddDataset(Histogram(x, probes, precision, "BernoulliRandomVariable p=0.5")); + + gnuplots.AddPlot(plot); + std::cout << "done" << std::endl; + } + { std::string gnuFile = plotFile + ".plt"; std::cout << "Writing Gnuplot file: " << gnuFile << "..." << std::flush; diff --git a/src/core/examples/sample-rng-plot.py b/src/core/examples/sample-rng-plot.py index 936ec3121..32304b9c3 100644 --- a/src/core/examples/sample-rng-plot.py +++ b/src/core/examples/sample-rng-plot.py @@ -1,18 +1,17 @@ -# -*- Mode:Python; -*- -# /* -# * 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 -# */ +# +# 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 +# ## @file # @ingroup core-examples @@ -23,18 +22,26 @@ # This is adapted from Gustavo Carneiro's ns-3 tutorial -import numpy as np -import matplotlib.pyplot as plt -import sys import argparse -from ns import ns +import sys + +import matplotlib.pyplot as plt +import numpy as np + +## Import ns-3 +try: + from ns import ns +except ModuleNotFoundError: + raise SystemExit( + "Error: ns3 Python module not found;" + " Python bindings may not be enabled" + " or your PYTHONPATH might not be properly configured" + ) def main(): parser = argparse.ArgumentParser("sample-rng-plot") - parser.add_argument("--not-blocking", - action="store_true", - default=False) + parser.add_argument("--not-blocking", action="store_true", default=False) args = parser.parse_args(sys.argv[1:]) # mu, var = 100, 225 @@ -52,16 +59,16 @@ def main(): ## Make a probability density histogram density = 1 ## Plot color - facecolor = 'g' + facecolor = "g" ## Plot alpha value (transparency) alpha = 0.75 # We don't really need the plot results, we're just going to show it later. # n, bins, patches = plt.hist(x, 50, density=1, facecolor='g', alpha=0.75) - n, bins, patches = plt.hist(x, 50, density=True, facecolor='g', alpha=0.75) + n, bins, patches = plt.hist(x, 50, density=True, facecolor="g", alpha=0.75) - plt.title('ns-3 histogram') - plt.text(60, .025, r'$\mu=100,\ \sigma=15$') + plt.title("ns-3 histogram") + plt.text(60, 0.025, r"$\mu=100,\ \sigma=15$") plt.axis([40, 160, 0, 0.03]) plt.grid(True) plt.show(block=not args.not_blocking) diff --git a/src/core/examples/sample-simulator.py b/src/core/examples/sample-simulator.py index a8bb55ee7..b52330f91 100755 --- a/src/core/examples/sample-simulator.py +++ b/src/core/examples/sample-simulator.py @@ -1,22 +1,21 @@ -# -*- Mode:Python; -*- -# /* -# * Copyright (c) 2010 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 -# */ +# +# Copyright (c) 2010 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 +# # # Python version of sample-simulator.cc @@ -25,20 +24,31 @@ # \ingroup simulator # Python example program demonstrating use of various Schedule functions. +## Import ns-3 +try: + from ns import ns +except ModuleNotFoundError: + raise SystemExit( + "Error: ns3 Python module not found;" + " Python bindings may not be enabled" + " or your PYTHONPATH might not be properly configured" + ) -from ns import ns ## Example function - triggered at a random time. ## \return None. def RandomFunction(): - print ("RandomFunction received event at", ns.core.Simulator.Now().GetSeconds(), "s") + print("RandomFunction received event at", ns.core.Simulator.Now().GetSeconds(), "s") + ## Example function - triggered if an event is canceled (should not be called). ## \return None. def CancelledEvent(): - print ("I should never be called... ") + print("I should never be called... ") -ns.cppyy.cppdef(""" + +ns.cppyy.cppdef( + """ #include "CPyCppyy/API.h" using namespace ns3; @@ -100,7 +110,8 @@ ns.cppyy.cppdef(""" { return MakeEvent(&CancelledFunctionCpp); } - """) + """ +) def main(argv): @@ -126,6 +137,8 @@ def main(argv): ns.core.Simulator.Destroy() -if __name__ == '__main__': + +if __name__ == "__main__": import sys + main(sys.argv) diff --git a/src/core/model/default-simulator-impl.cc b/src/core/model/default-simulator-impl.cc index 80742025c..f22bc6dca 100644 --- a/src/core/model/default-simulator-impl.cc +++ b/src/core/model/default-simulator-impl.cc @@ -209,11 +209,11 @@ DefaultSimulatorImpl::Stop() m_stop = true; } -void +EventId DefaultSimulatorImpl::Stop(const Time& delay) { NS_LOG_FUNCTION(this << delay.GetTimeStep()); - Simulator::Schedule(delay, &Simulator::Stop); + return Simulator::Schedule(delay, &Simulator::Stop); } // diff --git a/src/core/model/default-simulator-impl.h b/src/core/model/default-simulator-impl.h index e7edcc542..4a87e7dab 100644 --- a/src/core/model/default-simulator-impl.h +++ b/src/core/model/default-simulator-impl.h @@ -61,7 +61,7 @@ class DefaultSimulatorImpl : public SimulatorImpl void Destroy() override; bool IsFinished() const override; void Stop() override; - void Stop(const Time& delay) override; + EventId Stop(const Time& delay) override; EventId Schedule(const Time& delay, EventImpl* event) override; void ScheduleWithContext(uint32_t context, const Time& delay, EventImpl* event) override; EventId ScheduleNow(EventImpl* event) override; diff --git a/src/core/model/deprecated.h b/src/core/model/deprecated.h index 36a787d6e..eb6035e5b 100644 --- a/src/core/model/deprecated.h +++ b/src/core/model/deprecated.h @@ -74,6 +74,13 @@ */ #define NS_DEPRECATED(msg) [[deprecated(msg)]] +/** + * \ingroup core + * \def NS_DEPRECATED_3_41 + * Tag for things deprecated in version ns-3.41. + */ +#define NS_DEPRECATED_3_41(msg) NS_DEPRECATED(msg) + /** * \ingroup core * \def NS_DEPRECATED_3_40 @@ -81,32 +88,4 @@ */ #define NS_DEPRECATED_3_40(msg) NS_DEPRECATED(msg) -/** - * \ingroup core - * \def NS_DEPRECATED_3_39 - * Tag for things deprecated in version ns-3.39. - */ -#define NS_DEPRECATED_3_39(msg) NS_DEPRECATED(msg) - -/** - * \ingroup core - * \def NS_DEPRECATED_3_38 - * Tag for things deprecated in version ns-3.38. - */ -#define NS_DEPRECATED_3_38(msg) NS_DEPRECATED(msg) - -/** - * \ingroup core - * \def NS_DEPRECATED_3_37 - * Tag for things deprecated in version ns-3.37. - */ -#define NS_DEPRECATED_3_37(msg) NS_DEPRECATED(msg) - -/** - * \ingroup core - * \def NS_DEPRECATED_3_36 - * Tag for things deprecated in version ns-3.36. - */ -#define NS_DEPRECATED_3_36(msg) NS_DEPRECATED(msg) - #endif /* NS3_DEPRECATED_H */ diff --git a/src/core/model/enum.cc b/src/core/model/enum.cc deleted file mode 100644 index 907c6fa57..000000000 --- a/src/core/model/enum.cc +++ /dev/null @@ -1,214 +0,0 @@ -/* - * 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 - */ -#include "enum.h" - -#include "fatal-error.h" -#include "log.h" - -#include // find_if -#include // std::accumulate -#include - -/** - * \file - * \ingroup attribute_Enum - * ns3::EnumValue attribute value implementation. - */ - -namespace ns3 -{ - -NS_LOG_COMPONENT_DEFINE("Enum"); - -EnumValue::EnumValue() - : m_value() -{ - NS_LOG_FUNCTION(this); -} - -EnumValue::EnumValue(int value) - : m_value(value) -{ - NS_LOG_FUNCTION(this << value); -} - -void -EnumValue::Set(int value) -{ - NS_LOG_FUNCTION(this << value); - m_value = value; -} - -int -EnumValue::Get() const -{ - NS_LOG_FUNCTION(this); - return m_value; -} - -Ptr -EnumValue::Copy() const -{ - NS_LOG_FUNCTION(this); - return ns3::Create(*this); -} - -std::string -EnumValue::SerializeToString(Ptr checker) const -{ - NS_LOG_FUNCTION(this << checker); - const auto p = dynamic_cast(PeekPointer(checker)); - NS_ASSERT(p != nullptr); - std::string name = p->GetName(m_value); - return name; -} - -bool -EnumValue::DeserializeFromString(std::string value, Ptr checker) -{ - NS_LOG_FUNCTION(this << value << checker); - const auto p = dynamic_cast(PeekPointer(checker)); - NS_ASSERT(p != nullptr); - m_value = p->GetValue(value); - return true; -} - -EnumChecker::EnumChecker() -{ - NS_LOG_FUNCTION(this); -} - -void -EnumChecker::AddDefault(int value, std::string name) -{ - NS_LOG_FUNCTION(this << value << name); - m_valueSet.emplace_front(value, name); -} - -void -EnumChecker::Add(int value, std::string name) -{ - NS_LOG_FUNCTION(this << value << name); - m_valueSet.emplace_back(value, name); -} - -std::string -EnumChecker::GetName(int value) const -{ - auto it = std::find_if(m_valueSet.begin(), m_valueSet.end(), [value](Value v) { - return v.first == value; - }); - NS_ASSERT_MSG(it != m_valueSet.end(), - "invalid enum value " << value << "! Missed entry in MakeEnumChecker?"); - return it->second; -} - -int -EnumChecker::GetValue(const std::string name) const -{ - auto it = std::find_if(m_valueSet.begin(), m_valueSet.end(), [name](Value v) { - return v.second == name; - }); - NS_ASSERT_MSG( - it != m_valueSet.end(), - "name " - << name - << " is not a valid enum value. Missed entry in MakeEnumChecker?\nAvailable values: " - << std::accumulate(m_valueSet.begin(), - m_valueSet.end(), - std::string{}, - [](std::string a, Value v) { - if (a.empty()) - { - return v.second; - } - else - { - return std::move(a) + ", " + v.second; - } - })); - return it->first; -} - -bool -EnumChecker::Check(const AttributeValue& value) const -{ - NS_LOG_FUNCTION(this << &value); - const auto p = dynamic_cast(&value); - if (p == nullptr) - { - return false; - } - auto pvalue = p->Get(); - auto it = std::find_if(m_valueSet.begin(), m_valueSet.end(), [pvalue](Value v) { - return v.first == pvalue; - }); - return (it != m_valueSet.end()); -} - -std::string -EnumChecker::GetValueTypeName() const -{ - NS_LOG_FUNCTION(this); - return "ns3::EnumValue"; -} - -bool -EnumChecker::HasUnderlyingTypeInformation() const -{ - NS_LOG_FUNCTION(this); - return true; -} - -std::string -EnumChecker::GetUnderlyingTypeInformation() const -{ - NS_LOG_FUNCTION(this); - std::ostringstream oss; - bool moreValues = false; - for (const auto& i : m_valueSet) - { - oss << (moreValues ? "|" : "") << i.second; - moreValues = true; - } - return oss.str(); -} - -Ptr -EnumChecker::Create() const -{ - NS_LOG_FUNCTION(this); - return ns3::Create(); -} - -bool -EnumChecker::Copy(const AttributeValue& source, AttributeValue& destination) const -{ - NS_LOG_FUNCTION(this << &source << &destination); - const auto src = dynamic_cast(&source); - auto dst = dynamic_cast(&destination); - if (src == nullptr || dst == nullptr) - { - return false; - } - *dst = *src; - return true; -} - -} // namespace ns3 diff --git a/src/core/model/enum.h b/src/core/model/enum.h index 4a743d4d0..3849abd79 100644 --- a/src/core/model/enum.h +++ b/src/core/model/enum.h @@ -22,7 +22,12 @@ #include "attribute-accessor-helper.h" #include "attribute.h" +#include // find_if #include +#include // std::accumulate +#include +#include +#include /** * \file @@ -52,6 +57,7 @@ namespace ns3 * EnumValue (RipNg::NO_SPLIT_HORIZON)); * \endcode */ +template class EnumValue : public AttributeValue { public: @@ -61,10 +67,10 @@ class EnumValue : public AttributeValue * * \param [in] value The value to begin with. */ - EnumValue(int value); - void Set(int value); - int Get() const; - template + EnumValue(T value); + void Set(T value); + T Get() const; + bool GetAccessor(T& value) const; Ptr Copy() const override; @@ -72,17 +78,48 @@ class EnumValue : public AttributeValue bool DeserializeFromString(std::string value, Ptr checker) override; private: - int m_value; //!< The stored integer value. + T m_value; //!< The stored value. }; template -bool -EnumValue::GetAccessor(T& value) const +EnumValue::EnumValue() = default; + +template +EnumValue::EnumValue(T value) + : m_value(value) { - value = T(m_value); +} + +template +void +EnumValue::Set(T value) +{ + m_value = value; +} + +template +T +EnumValue::Get() const +{ + return m_value; +} + +template +bool +EnumValue::GetAccessor(T& value) const +{ + value = static_cast(m_value); return true; } +template +Ptr +EnumValue::Copy() const +{ + return Create(*this); +} + +template class EnumChecker : public AttributeChecker { public: @@ -93,27 +130,27 @@ class EnumChecker : public AttributeChecker * \param [in] value The value. * \param [in] name Then enum symbol name. */ - void AddDefault(int value, std::string name); + void AddDefault(T value, std::string name); /** * Add a new value. * \param [in] value The value. * \param [in] name The enum symbol name. */ - void Add(int value, std::string name); + void Add(T value, std::string name); /** * Get the enum symbol name by value. * \param [in] value The value. * \return The enum symbol name. */ - std::string GetName(int value) const; + std::string GetName(T value) const; /** * Get the enum value by name. * \param [in] name Then enum symbol name. * \returns The enum value. */ - int GetValue(const std::string name) const; + T GetValue(const std::string name) const; // Inherited bool Check(const AttributeValue& value) const override; @@ -125,19 +162,13 @@ class EnumChecker : public AttributeChecker private: /** Type for the pair value, name */ - typedef std::pair Value; + using Value = std::pair; /** Type of container for storing Enum values and symbol names. */ - typedef std::list ValueSet; + using ValueSet = std::list; /** The stored Enum values and symbol names. */ ValueSet m_valueSet; }; -template -Ptr MakeEnumAccessor(T1 a1); - -template -Ptr MakeEnumAccessor(T1 a1, T2 a2); - /** * Make an EnumChecker pre-configured with a set of allowed * values by name. @@ -152,17 +183,17 @@ Ptr MakeEnumAccessor(T1 a1, T2 a2); * \see AttributeChecker * * \tparam Ts The type list of additional parameters. Additional parameters - * should be int, string pairs. + * should be T, string pairs. * \returns The AttributeChecker * \param [in] v The default enum value. * \param [in] n The corresponding name. * \param [in] args Any additional arguments. */ -template +template Ptr -MakeEnumChecker(int v, std::string n, Ts... args) +MakeEnumChecker(T v, std::string n, Ts... args) { - Ptr checker = Create(); + Ptr> checker = Create>(); checker->AddDefault(v, n); return MakeEnumChecker(checker, args...); } @@ -171,17 +202,16 @@ MakeEnumChecker(int v, std::string n, Ts... args) * Handler for enum value, name pairs other than the default. * * \tparam Ts The type list of additional parameters. Additional parameters - * should be in int, string pairs. + * should be T, string pairs. * \returns The AttributeChecker * \param [in] checker The AttributeChecker. * \param [in] v The next enum value. * \param [in] n The corresponding name. * \param [in] args Any additional arguments. */ - -template +template Ptr -MakeEnumChecker(Ptr checker, int v, std::string n, Ts... args) +MakeEnumChecker(Ptr> checker, T v, std::string n, Ts... args) { checker->Add(v, n); return MakeEnumChecker(checker, args...); @@ -194,24 +224,171 @@ MakeEnumChecker(Ptr checker, int v, std::string n, Ts... args) * \param [in] checker The AttributeChecker. */ // inline to allow tail call optimization +template inline Ptr -MakeEnumChecker(Ptr checker) +MakeEnumChecker(Ptr> checker) { return checker; } -template +template Ptr MakeEnumAccessor(T1 a1) { - return MakeAccessorHelper(a1); + return MakeAccessorHelper>(a1); } -template +template Ptr MakeEnumAccessor(T1 a1, T2 a2) { - return MakeAccessorHelper(a1, a2); + return MakeAccessorHelper>(a1, a2); +} + +template +std::string +EnumValue::SerializeToString(Ptr checker) const +{ + const auto p = dynamic_cast*>(PeekPointer(checker)); + NS_ASSERT(p != nullptr); + std::string name = p->GetName(m_value); + return name; +} + +template +bool +EnumValue::DeserializeFromString(std::string value, Ptr checker) +{ + const auto p = dynamic_cast*>(PeekPointer(checker)); + NS_ASSERT(p != nullptr); + m_value = p->GetValue(value); + return true; +} + +template +EnumChecker::EnumChecker() +{ +} + +template +void +EnumChecker::AddDefault(T value, std::string name) +{ + m_valueSet.emplace_front(value, name); +} + +template +void +EnumChecker::Add(T value, std::string name) +{ + m_valueSet.emplace_back(value, name); +} + +template +std::string +EnumChecker::GetName(T value) const +{ + auto it = std::find_if(m_valueSet.begin(), m_valueSet.end(), [value](Value v) { + return v.first == value; + }); + + NS_ASSERT_MSG(it != m_valueSet.end(), + "invalid enum value " << static_cast(value) + << "! Missed entry in MakeEnumChecker?"); + return it->second; +} + +template +T +EnumChecker::GetValue(const std::string name) const +{ + auto it = std::find_if(m_valueSet.begin(), m_valueSet.end(), [name](Value v) { + return v.second == name; + }); + NS_ASSERT_MSG( + it != m_valueSet.end(), + "name " + << name + << " is not a valid enum value. Missed entry in MakeEnumChecker?\nAvailable values: " + << std::accumulate(m_valueSet.begin(), + m_valueSet.end(), + std::string{}, + [](std::string a, Value v) { + if (a.empty()) + { + return v.second; + } + else + { + return std::move(a) + ", " + v.second; + } + })); + return it->first; +} + +template +bool +EnumChecker::Check(const AttributeValue& value) const +{ + const auto p = dynamic_cast*>(&value); + if (!p) + { + return false; + } + auto pvalue = p->Get(); + auto it = std::find_if(m_valueSet.begin(), m_valueSet.end(), [pvalue](Value v) { + return v.first == pvalue; + }); + return (it != m_valueSet.end()); +} + +template +std::string +EnumChecker::GetValueTypeName() const +{ + return "ns3::EnumValue<" + std::string(typeid(T).name()) + ">"; +} + +template +bool +EnumChecker::HasUnderlyingTypeInformation() const +{ + return true; +} + +template +std::string +EnumChecker::GetUnderlyingTypeInformation() const +{ + std::ostringstream oss; + bool moreValues = false; + for (const auto& i : m_valueSet) + { + oss << (moreValues ? "|" : "") << i.second; + moreValues = true; + } + return oss.str(); +} + +template +Ptr +EnumChecker::Create() const +{ + return ns3::Create>(); +} + +template +bool +EnumChecker::Copy(const AttributeValue& source, AttributeValue& destination) const +{ + const auto src = dynamic_cast*>(&source); + auto dst = dynamic_cast*>(&destination); + if (!src || !dst) + { + return false; + } + *dst = *src; + return true; } } // namespace ns3 diff --git a/src/core/model/int64x64-128.cc b/src/core/model/int64x64-128.cc index 38e1cfbd9..daf105741 100644 --- a/src/core/model/int64x64-128.cc +++ b/src/core/model/int64x64-128.cc @@ -225,7 +225,7 @@ int64x64_t::Invert(const uint64_t v) a <<= 64; int64x64_t result; result._v = Udiv(a, v); - int64x64_t tmp = int64x64_t(v, false); + int64x64_t tmp(v, 0); tmp.MulByInvert(result); if (tmp.GetHigh() != 1) { diff --git a/src/core/model/log-macros-enabled.h b/src/core/model/log-macros-enabled.h index 4d9bceb10..2251178dd 100644 --- a/src/core/model/log-macros-enabled.h +++ b/src/core/model/log-macros-enabled.h @@ -189,7 +189,9 @@ NS_LOG_APPEND_CONTEXT; \ NS_LOG_APPEND_FUNC_PREFIX; \ NS_LOG_APPEND_LEVEL_PREFIX(level); \ + auto flags = std::clog.setf(std::ios_base::boolalpha); \ std::clog << msg << std::endl; \ + std::clog.flags(flags); \ } \ } while (false) @@ -245,7 +247,9 @@ NS_LOG_APPEND_NODE_PREFIX; \ NS_LOG_APPEND_CONTEXT; \ std::clog << g_log.Name() << ":" << __FUNCTION__ << "("; \ + auto flags = std::clog.setf(std::ios_base::boolalpha); \ ns3::ParameterLogger(std::clog) << parameters; \ + std::clog.flags(flags); \ std::clog << ")" << std::endl; \ } \ } while (false) @@ -261,7 +265,9 @@ NS_LOG_CONDITION \ do \ { \ + auto flags = std::clog.setf(std::ios_base::boolalpha); \ std::clog << msg << std::endl; \ + std::clog.flags(flags); \ } while (false) #endif /* NS3_LOG_ENABLE */ diff --git a/src/core/model/log.cc b/src/core/model/log.cc index 7342615e3..8f36fd907 100644 --- a/src/core/model/log.cc +++ b/src/core/model/log.cc @@ -535,36 +535,4 @@ ParameterLogger::CommaRest() } } -template <> -ParameterLogger& -ParameterLogger::operator<< (const std::string& param) -{ - CommaRest(); - m_os << "\"" << param << "\""; - return *this; -} - -ParameterLogger& -ParameterLogger::operator<<(const char* param) -{ - (*this) << std::string(param); - return *this; -} - -template <> -ParameterLogger& -ParameterLogger::operator<< (const int8_t param) -{ - (*this) << static_cast(param); - return *this; -} - -template <> -ParameterLogger& -ParameterLogger::operator<< (const uint8_t param) -{ - (*this) << static_cast(param); - return *this; -} - } // namespace ns3 diff --git a/src/core/model/log.h b/src/core/model/log.h index 551c0043c..cfc2f90e0 100644 --- a/src/core/model/log.h +++ b/src/core/model/log.h @@ -447,25 +447,11 @@ class ParameterLogger /** * Write a function parameter on the output stream, * separating parameters after the first by `,` strings. - * Overload for arithmetic types (integral type or floating point type), - * enabling the parameter to be passed by value. * * \param [in] param The function parameter. * \return This ParameterLogger, so it's chainable. */ - template >> - ParameterLogger& operator<<(T param); - - /** - * Write a function parameter on the output stream, - * separating parameters after the first by `,` strings. - * Overload for non-arithmetic types, enabling the parameter - * to be passed by reference. - * - * \param [in] param The function parameter. - * \return This ParameterLogger, so it's chainable. - */ - template >> + template ParameterLogger& operator<<(const T& param); /** @@ -477,14 +463,6 @@ class ParameterLogger template ParameterLogger& operator<<(const std::vector& vector); - /** - * Overload for C-strings. - * - * \param [in] param The C-string - * \return This ParameterLogger, so it's chainable. - */ - ParameterLogger& operator<<(const char* param); - private: /** Add `, ` before every parameter after the first. */ void CommaRest(); @@ -493,21 +471,26 @@ class ParameterLogger std::ostream& m_os; //!< Underlying output stream. }; -template -ParameterLogger& -ParameterLogger::operator<<(T param) -{ - CommaRest(); - m_os << param; - return *this; -} - -template +template ParameterLogger& ParameterLogger::operator<<(const T& param) { CommaRest(); - m_os << param; + + if constexpr (std::is_convertible_v) + { + m_os << "\"" << param << "\""; + } + else if constexpr (std::is_arithmetic_v) + { + // Use + unary operator to cast uint8_t / int8_t to uint32_t / int32_t, respectively + m_os << +param; + } + else + { + m_os << param; + } + return *this; } @@ -522,30 +505,6 @@ ParameterLogger::operator<<(const std::vector& vector) return *this; } -/** - * Specialization for strings. - * \param [in] param The function parameter. - * \return This ParameterLogger, so it's chainable. - */ -template <> -ParameterLogger& ParameterLogger::operator<< (const std::string& param); - -/** - * Specialization for int8_t. - * \param [in] param The function parameter. - * \return This ParameterLogger, so it's chainable. - */ -template <> -ParameterLogger& ParameterLogger::operator<< (const int8_t param); - -/** - * Specialization for uint8_t. - * \param [in] param The function parameter. - * \return This ParameterLogger, so it's chainable. - */ -template <> -ParameterLogger& ParameterLogger::operator<< (const uint8_t param); - } // namespace ns3 /**@}*/ // \ingroup logging diff --git a/src/core/model/matrix-array.h b/src/core/model/matrix-array.h index 25a816a55..34305e214 100644 --- a/src/core/model/matrix-array.h +++ b/src/core/model/matrix-array.h @@ -83,7 +83,7 @@ class MatrixArray : public ValArray { public: // instruct the compiler to generate the default constructor - MatrixArray() = default; + MatrixArray() = default; /** * \brief Constructor "pages" number of matrices that are of size "numRows"x"numCols", * and are initialized with all-zero elements. @@ -92,25 +92,25 @@ class MatrixArray : public ValArray * \param numCols the number of columns * \param numPages the number of pages */ - MatrixArray(size_t numRows, size_t numCols = 1, size_t numPages = 1); + MatrixArray(size_t numRows, size_t numCols = 1, size_t numPages = 1); /** * \brief Constructor creates a single array of values.size () elements and 1 column, * and uses std::valarray values to initialize the elements. * \param values std::valarray that will be used to initialize elements of 1D array */ - explicit MatrixArray(const std::valarray& values); + explicit MatrixArray(const std::valarray& values); /** * \brief Constructor creates a single array of values.size () elements and 1 column, * and moves std::valarray values to initialize the elements. * \param values std::valarray that will be moved to initialize elements of 1D array */ - MatrixArray(std::valarray&& values); + MatrixArray(std::valarray&& values); /** * \brief Constructor creates a single array of values.size () elements and 1 column, * and uses std::vector values to initialize the elements. * \param values std::vector that will be used to initialize elements of 1D array */ - explicit MatrixArray(const std::vector& values); + explicit MatrixArray(const std::vector& values); /** * \brief Constructor creates a single matrix of numRows and numCols, and uses * std::valarray values to initialize the elements. @@ -118,7 +118,7 @@ class MatrixArray : public ValArray * \param numCols the number of columns * \param values std::valarray that will be used to initialize elements of 3D array */ - MatrixArray(size_t numRows, size_t numCols, const std::valarray& values); + MatrixArray(size_t numRows, size_t numCols, const std::valarray& values); /** * \brief Constructor creates a single matrix of numRows and numCols, and moves * std::valarray values to initialize the elements. @@ -126,7 +126,7 @@ class MatrixArray : public ValArray * \param numCols the number of columns * \param values std::valarray that will be moved to initialize elements of 3D array */ - MatrixArray(size_t numRows, size_t numCols, std::valarray&& values); + MatrixArray(size_t numRows, size_t numCols, std::valarray&& values); /** * \brief Constructor creates the array of numPages matrices of numRows x numCols dimensions, * and uses std::valarray values to initialize all the elements. @@ -135,7 +135,7 @@ class MatrixArray : public ValArray * \param numPages the number of pages * \param values std::valarray that will be used to initialize elements of 3D array */ - MatrixArray(size_t numRows, size_t numCols, size_t numPages, const std::valarray& values); + MatrixArray(size_t numRows, size_t numCols, size_t numPages, const std::valarray& values); /** * \brief Constructor creates the array of numPages matrices of numRows x numCols dimensions, * and moves std::valarray values to initialize all the elements. @@ -144,49 +144,32 @@ class MatrixArray : public ValArray * \param numPages the number of pages * \param values std::valarray that will be used to initialize elements of 3D array */ - MatrixArray(size_t numRows, size_t numCols, size_t numPages, std::valarray&& values); - /** instruct the compiler to generate the implicitly declared destructor*/ - ~MatrixArray() override = default; - /** instruct the compiler to generate the implicitly declared copy constructor*/ - MatrixArray(const MatrixArray&) = default; - /** - * \brief Copy assignment operator. - * Instruct the compiler to generate the implicitly declared copy assignment operator. - * \return a reference to the result of the assignment - */ - MatrixArray& operator=(const MatrixArray&) = default; - /** instruct the compiler to generate the implicitly declared move constructor*/ - MatrixArray(MatrixArray&&) = default; - /** - * \brief Move assignment operator. - * Instruct the compiler to generate the implicitly declared move assignment operator. - * \return a reference to the result of the assignment - */ - MatrixArray& operator=(MatrixArray&&) = default; + MatrixArray(size_t numRows, size_t numCols, size_t numPages, std::valarray&& values); + /** * \brief Element-wise multiplication with a scalar value. * \param rhs is a scalar value of type T * \returns The matrix in which each element has been multiplied by the given * scalar value. */ - MatrixArray operator*(const T& rhs) const; + MatrixArray operator*(const T& rhs) const; /** * \brief operator+ definition for MatrixArray. * \param rhs The rhs MatrixArray object * \returns The result of operator+ of this MatrixArray and rhs MatrixArray */ - MatrixArray operator+(const MatrixArray& rhs) const; + MatrixArray operator+(const MatrixArray& rhs) const; /** * \brief binary operator- definition for MatrixArray. * \param rhs The rhs MatrixArray object * \returns The result of operator- of this MatrixArray and rhs MatrixArray */ - MatrixArray operator-(const MatrixArray& rhs) const; + MatrixArray operator-(const MatrixArray& rhs) const; /** * \brief unary operator- definition for MatrixArray. * \return the result of the operator- */ - MatrixArray operator-() const; + MatrixArray operator-() const; /** * \brief Page-wise matrix multiplication. * This operator interprets the 3D array as an array of matrices, @@ -198,14 +181,14 @@ class MatrixArray : public ValArray * \param rhs is another MatrixArray instance * \returns The array of results of matrix multiplications. */ - MatrixArray operator*(const MatrixArray& rhs) const; + MatrixArray operator*(const MatrixArray& rhs) const; /** * \brief This operator interprets the 3D array as an array of matrices, * and performs a linear algebra operation on each of the matrices (pages), * i.e., transposes the matrix or array of matrices definition for MatrixArray. * \return The resulting MatrixArray composed of the array of transposed matrices. */ - MatrixArray Transpose() const; + MatrixArray Transpose() const; /** *\brief Multiply each matrix in the array by the left and the right matrix. * For each page of this MatrixArray the operation performed is @@ -228,8 +211,8 @@ class MatrixArray : public ValArray * \returns Returns the result of the multiplication which is a 3D MatrixArray * with dimensions J x K x P as explained previously. */ - MatrixArray MultiplyByLeftAndRightMatrix(const MatrixArray& lMatrix, - const MatrixArray& rMatrix) const; + MatrixArray MultiplyByLeftAndRightMatrix(const MatrixArray& lMatrix, + const MatrixArray& rMatrix) const; using ValArray::GetPagePtr; using ValArray::EqualDims; diff --git a/src/core/model/nstime.h b/src/core/model/nstime.h index de142ccfd..85cb00259 100644 --- a/src/core/model/nstime.h +++ b/src/core/model/nstime.h @@ -271,9 +271,10 @@ class Time * - `d` (days) * - `y` (years) * - * There can be no white space between the numerical portion - * and the units. Any otherwise malformed string causes a fatal error to - * occur. + * There must be no whitespace between the numerical portion + * and the unit. If the string only contains a number, it is treated as seconds. + * Any otherwise malformed string causes a fatal error to occur. + * * \param [in] s The string to parse into a Time */ explicit Time(const std::string& s); diff --git a/src/core/model/ptr.h b/src/core/model/ptr.h index 0ac19f0a5..06a988b01 100644 --- a/src/core/model/ptr.h +++ b/src/core/model/ptr.h @@ -21,7 +21,6 @@ #define PTR_H #include "assert.h" -#include "deprecated.h" #include #include @@ -80,23 +79,6 @@ class Ptr /** The pointer. */ T* m_ptr; - /** - * Helper to test for null pointer. - * - * \note This has been deprecated; \see operator bool() instead. - * - * This supports the "safe-bool" idiom, see `operator Tester * ()` - */ - // Don't deprecate the class because the warning fires - // every time ptr.h is merely included, masking the real uses of Tester - // Leave the macro here so we can find this later to actually remove it. - class /* NS_DEPRECATED_3_37 ("see operator bool") */ Tester - { - public: - // Delete operator delete to avoid misuse - void operator delete(void*) = delete; - }; - /** Interoperate with const instances. */ friend class Ptr; @@ -197,23 +179,6 @@ class Ptr */ T& operator*(); - /** - * Test for non-NULL Ptr. - * - * \note This has been deprecated; \see operator bool() instead. - * - * This enables simple pointer checks like - * \code - * Ptr<...> p = ...; - * if (p) ... - * \endcode - * This also disables deleting a Ptr - * - * This supports the "safe-bool" idiom; see [More C++ Idioms/Safe - * bool](https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Safe_bool) - */ - NS_DEPRECATED_3_37("see operator bool") - operator Tester*() const; /** * Test for non-NULL pointer. * @@ -773,17 +738,6 @@ Ptr::operator*() return *m_ptr; } -template -Ptr::operator Tester*() const // NS_DEPRECATED_3_37 -{ - if (m_ptr == 0) - { - return 0; - } - static Tester test; - return &test; -} - template Ptr::operator bool() const { diff --git a/src/core/model/random-variable-stream.cc b/src/core/model/random-variable-stream.cc index 229b96829..4364419ea 100644 --- a/src/core/model/random-variable-stream.cc +++ b/src/core/model/random-variable-stream.cc @@ -1738,4 +1738,123 @@ EmpiricalRandomVariable::Validate() m_validated = true; } +NS_OBJECT_ENSURE_REGISTERED(BinomialRandomVariable); + +TypeId +BinomialRandomVariable::GetTypeId() +{ + static TypeId tid = + TypeId("ns3::BinomialRandomVariable") + .SetParent() + .SetGroupName("Core") + .AddConstructor() + .AddAttribute("Trials", + "The number of trials.", + IntegerValue(10), + MakeIntegerAccessor(&BinomialRandomVariable::m_trials), + MakeIntegerChecker(0)) + .AddAttribute("Probability", + "The probability of success in each trial.", + DoubleValue(0.5), + MakeDoubleAccessor(&BinomialRandomVariable::m_probability), + MakeDoubleChecker(0)); + return tid; +} + +BinomialRandomVariable::BinomialRandomVariable() +{ + // m_trials and m_probability are initialized after constructor by attributes + NS_LOG_FUNCTION(this); +} + +double +BinomialRandomVariable::GetValue(uint32_t trials, double probability) +{ + NS_LOG_FUNCTION(this << trials << probability); + + double successes = 0; + + for (uint32_t i = 0; i < trials; ++i) + { + double v = Peek()->RandU01(); + if (IsAntithetic()) + { + v = (1 - v); + } + + if (v <= probability) + { + successes += 1; + } + } + + return successes; +} + +uint32_t +BinomialRandomVariable::GetInteger(uint32_t trials, uint32_t probability) +{ + NS_LOG_FUNCTION(this << trials << probability); + return static_cast(GetValue(trials, probability)); +} + +double +BinomialRandomVariable::GetValue() +{ + NS_LOG_FUNCTION(this); + return GetValue(m_trials, m_probability); +} + +NS_OBJECT_ENSURE_REGISTERED(BernoulliRandomVariable); + +TypeId +BernoulliRandomVariable::GetTypeId() +{ + static TypeId tid = + TypeId("ns3::BernoulliRandomVariable") + .SetParent() + .SetGroupName("Core") + .AddConstructor() + .AddAttribute("Probability", + "The probability of the random variable returning a value of 1.", + DoubleValue(0.5), + MakeDoubleAccessor(&BernoulliRandomVariable::m_probability), + MakeDoubleChecker(0)); + return tid; +} + +BernoulliRandomVariable::BernoulliRandomVariable() +{ + // m_probability is initialized after constructor by attributes + NS_LOG_FUNCTION(this); +} + +double +BernoulliRandomVariable::GetValue(double probability) +{ + NS_LOG_FUNCTION(this << probability); + + double v = Peek()->RandU01(); + if (IsAntithetic()) + { + v = (1 - v); + } + + return (v <= probability) ? 1.0 : 0.0; +} + +uint32_t +BernoulliRandomVariable::GetInteger(uint32_t probability) +{ + NS_LOG_FUNCTION(this << probability); + return static_cast(GetValue(probability)); +} + +double +BernoulliRandomVariable::GetValue() +{ + NS_LOG_FUNCTION(this); + return GetValue(m_probability); +} + } // namespace ns3 diff --git a/src/core/model/random-variable-stream.h b/src/core/model/random-variable-stream.h index e7b398995..7ddb6f9e7 100644 --- a/src/core/model/random-variable-stream.h +++ b/src/core/model/random-variable-stream.h @@ -18,6 +18,7 @@ * Authors: Rajib Bhattacharjea * Hadi Arbabi * Mathieu Lacage + * Alessio Bugetti * * Modified by Mitch Watrous * @@ -2074,6 +2075,202 @@ class EmpiricalRandomVariable : public RandomVariableStream }; // class EmpiricalRandomVariable +/** + * \ingroup randomvariable + * \brief The binomial distribution Random Number Generator (RNG). + * + * This class supports the creation of objects that return random numbers + * from a fixed binomial distribution. It also supports the generation of + * single random numbers from various binomial distributions. + * + * The probability mass function of a binomial variable + * is defined as: + * + * \f[ + * P(k; n, p) = \binom{n}{k} p^k (1-p)^{n-k}, \\ + * \quad k \in [0, n] + * \f] + * + * where \f$ n \f$ is the number of trials and \f$ p \f$ is the probability + * of success in each trial. The mean of this distribution + * is \f$ \mu = np \f$ and the variance is \f$ \sigma^2 = np(1-p) \f$. + * + * The Binomial RNG value \f$n\f$ for a given number of trials \f$ n \f$ + * and success probability \f$ p \f$ is generated by + * + * \f[ + * k = \sum_{i=1}^{n} I(u_i \leq p) + * \f] + * + * where \f$u_i\f$ is a uniform random variable on [0,1) for each trial, + * and \f$I\f$ is an indicator function that is 1 if \f$u_i \leq p\f$ and 0 otherwise. + * The sum of these indicator functions over all trials gives the total + * number of successes, which is the value of the binomial random variable. + * + * \par Example + * + * Here is an example of how to use this class: + * \code{.cc} + * uint32_t trials = 10; + * double probability = 0.5; + * + * Ptr x = CreateObject (); + * x->SetAttribute ("Trials", UintegerValue (trials)); + * x->SetAttribute ("Probability", DoubleValue (probability)); + * + * double successes = x->GetValue (); + * \endcode + * + * \par Antithetic Values. + * + * If an instance of this RNG is configured to return antithetic values, + * the actual value returned, \f$n'\f$, for the Binomial process is determined by: + * + * \f[ + * k' = \sum_{i=1}^{n} I((1 - u_i) \leq p) + * \f] + * + * where \f$u_i\f$ is a uniform random variable on [0,1) for each trial. + * The antithetic approach uses \f$(1 - u_i)\f$ instead of \f$u_i\f$ in the indicator function. + * + * @par Efficiency and Alternative Methods + * + * There are alternative methods for generating binomial distributions that may offer greater + * efficiency. However, this implementation opts for a simpler approach. Although not as efficient, + * this method was chosen for its simplicity and sufficiency in most applications. + */ +class BinomialRandomVariable : public RandomVariableStream +{ + public: + /** + * \brief Register this type. + * \return The object TypeId. + */ + static TypeId GetTypeId(); + + BinomialRandomVariable(); + + /** + * \copydoc GetValue() + * \param [in] trials Number of trials. + * \param [in] probability Probability of success in each trial. + * \return Returns a number within the range [0, trials] indicating the number of successful + * trials. + */ + double GetValue(uint32_t trials, double probability); + + /** + * \copydoc GetValue(uint32_t,double) + * This function is similar to GetValue(), but it returns a uint32_t instead of a double. + */ + uint32_t GetInteger(uint32_t trials, uint32_t probability); + + // Inherited + double GetValue() override; + using RandomVariableStream::GetInteger; + + private: + /** The number of trials. */ + uint32_t m_trials; + + /** The probability of success in each trial. */ + double m_probability; + +}; // class BinomialRandomVariable + +/** + * \ingroup randomvariable + * \brief The Bernoulli distribution Random Number Generator (RNG). + * + * This class supports the creation of objects that return random numbers + * from a fixed Bernoulli distribution. It also supports the generation of + * single random numbers from various Bernoulli distributions. + * + * The probability mass function of a Bernoulli variable + * is defined as: + * + * \f[ + * P(n; p) = p^n (1-p)^{1-n}, \\ + * \quad n \in \{0, 1\} + * \f] + * + * where \f$ p \f$ is the probability of success and n is the indicator of success, with n=1 + * representing success and n=0 representing failure. The mean of this distribution is \f$ \mu = p + * \f$ and the variance is \f$ \sigma^2 = p(1-p) \f$. + * + * The Bernoulli RNG value \f$n\f$ is generated by + * + * \f[ + * n = + * \begin{cases} + * 1 & \text{if } u \leq p \\ + * 0 & \text{otherwise} + * \end{cases} + * \f] + * + * where \f$u\f$ is a uniform random variable on [0,1) and \f$p\f$ is the probability of success. + * + * \par Example + * + * Here is an example of how to use this class: + * \code{.cc} + * double probability = 0.5; + * + * Ptr x = CreateObject (); + * x->SetAttribute ("Probability", DoubleValue (probability)); + * + * double success = x->GetValue (); + * \endcode + * + * \par Antithetic Values. + * + * If an instance of this RNG is configured to return antithetic values, + * the actual value returned, \f$x'\f$, is determined by: + * + * \f[ + * x' = + * \begin{cases} + * 1 & \text{if } (1 - u) \leq p \\ + * 0 & \text{otherwise} + * \end{cases} + * \f] + * + * where \f$u\f$ is a uniform random variable on [0,1) and \f$p\f$ is the probability of success. + */ +class BernoulliRandomVariable : public RandomVariableStream +{ + public: + /** + * \brief Register this type. + * \return The object TypeId. + */ + static TypeId GetTypeId(); + + BernoulliRandomVariable(); + + /** + * \copydoc GetValue() + * \param [in] probability Probability of success. + * \return Returns 1 if the trial is successful, or 0 if it is not. + */ + double GetValue(double probability); + + /** + * \copydoc GetValue(double) + * This function is similar to GetValue(), but it returns a uint32_t instead of a double. + */ + uint32_t GetInteger(uint32_t probability); + + // Inherited + double GetValue() override; + using RandomVariableStream::GetInteger; + + private: + /** The probability of success. */ + double m_probability; + +}; // class BernoulliRandomVariable + } // namespace ns3 #endif /* RANDOM_VARIABLE_STREAM_H */ diff --git a/src/core/model/realtime-simulator-impl.cc b/src/core/model/realtime-simulator-impl.cc index 9c4152dc6..526bfa86e 100644 --- a/src/core/model/realtime-simulator-impl.cc +++ b/src/core/model/realtime-simulator-impl.cc @@ -62,7 +62,8 @@ RealtimeSimulatorImpl::GetTypeId() "SynchronizationMode", "What to do if the simulation cannot keep up with real time.", EnumValue(SYNC_BEST_EFFORT), - MakeEnumAccessor(&RealtimeSimulatorImpl::SetSynchronizationMode), + MakeEnumAccessor( + &RealtimeSimulatorImpl::SetSynchronizationMode), MakeEnumChecker(SYNC_BEST_EFFORT, "BestEffort", SYNC_HARD_LIMIT, "HardLimit")) .AddAttribute("HardLimit", "Maximum acceptable real-time jitter (used in conjunction with " @@ -453,16 +454,15 @@ RealtimeSimulatorImpl::Run() } } - if (!process) + if (process) { - // Sleep until signalled - tsNow = m_synchronizer->Synchronize(tsNow, tsDelay); - - // Re-check event queue - continue; + ProcessOneEvent(); + } + else + { + // Sleep until signalled and re-check event queue + m_synchronizer->Synchronize(tsNow, tsDelay); } - - ProcessOneEvent(); } // @@ -498,11 +498,11 @@ RealtimeSimulatorImpl::Stop() m_stop = true; } -void +EventId RealtimeSimulatorImpl::Stop(const Time& delay) { NS_LOG_FUNCTION(this << delay); - Simulator::Schedule(delay, &Simulator::Stop); + return Simulator::Schedule(delay, &Simulator::Stop); } // diff --git a/src/core/model/realtime-simulator-impl.h b/src/core/model/realtime-simulator-impl.h index 4d2b6e56e..307693306 100644 --- a/src/core/model/realtime-simulator-impl.h +++ b/src/core/model/realtime-simulator-impl.h @@ -91,7 +91,7 @@ class RealtimeSimulatorImpl : public SimulatorImpl void Destroy() override; bool IsFinished() const override; void Stop() override; - void Stop(const Time& delay) override; + EventId Stop(const Time& delay) override; EventId Schedule(const Time& delay, EventImpl* event) override; void ScheduleWithContext(uint32_t context, const Time& delay, EventImpl* event) override; EventId ScheduleNow(EventImpl* event) override; diff --git a/src/core/model/rng-stream.cc b/src/core/model/rng-stream.cc index 75e3ac170..06b049f20 100644 --- a/src/core/model/rng-stream.cc +++ b/src/core/model/rng-stream.cc @@ -370,7 +370,7 @@ RngStream::RandU01() m_currentState[5] = p2; /* Combination */ - u = ((p1 > p2) ? (p1 - p2) * norm : (p1 - p2 + m1) * norm); + u = ((p1 > p2) ? (p1 - p2) * MRG32k3a::norm : (p1 - p2 + m1) * MRG32k3a::norm); return u; } diff --git a/src/core/model/simulation-singleton.h b/src/core/model/simulation-singleton.h index ed72b7a79..9f18b79e6 100644 --- a/src/core/model/simulation-singleton.h +++ b/src/core/model/simulation-singleton.h @@ -44,9 +44,9 @@ class SimulationSingleton { public: // Delete default constructor, copy constructor and assignment operator to avoid misuse - SimulationSingleton() = delete; - SimulationSingleton(const SimulationSingleton&) = delete; - SimulationSingleton& operator=(const SimulationSingleton&) = delete; + SimulationSingleton() = delete; + SimulationSingleton(const SimulationSingleton&) = delete; + SimulationSingleton& operator=(const SimulationSingleton&) = delete; /** * Get a pointer to the singleton instance. diff --git a/src/core/model/simulator-impl.h b/src/core/model/simulator-impl.h index e95395c31..9775e324d 100644 --- a/src/core/model/simulator-impl.h +++ b/src/core/model/simulator-impl.h @@ -61,7 +61,7 @@ class SimulatorImpl : public Object /** \copydoc Simulator::Stop() */ virtual void Stop() = 0; /** \copydoc Simulator::Stop(const Time&) */ - virtual void Stop(const Time& delay) = 0; + virtual EventId Stop(const Time& delay) = 0; /** \copydoc Simulator::Schedule(const Time&,const Ptr&) */ virtual EventId Schedule(const Time& delay, EventImpl* event) = 0; /** \copydoc Simulator::ScheduleWithContext(uint32_t,const Time&,EventImpl*) */ diff --git a/src/core/model/simulator.cc b/src/core/model/simulator.cc index 4d6233554..806cfa04a 100644 --- a/src/core/model/simulator.cc +++ b/src/core/model/simulator.cc @@ -54,6 +54,8 @@ namespace ns3 // of causing recursions leading to stack overflow NS_LOG_COMPONENT_DEFINE("Simulator"); +EventId Simulator::m_stopEvent; + /** * \ingroup simulator * \anchor GlobalValueSimulatorImplementationType @@ -188,11 +190,18 @@ Simulator::Stop() GetImpl()->Stop(); } -void +EventId Simulator::Stop(const Time& delay) { NS_LOG_FUNCTION(delay); - GetImpl()->Stop(delay); + m_stopEvent = GetImpl()->Stop(delay); + return m_stopEvent; +} + +EventId +Simulator::GetStopEvent() +{ + return m_stopEvent; } Time diff --git a/src/core/model/simulator.h b/src/core/model/simulator.h index 0a795a3c4..1e31d605a 100644 --- a/src/core/model/simulator.h +++ b/src/core/model/simulator.h @@ -166,8 +166,16 @@ class Simulator * or equal to the stop time. The stop time is relative to the * current simulation time. * @param [in] delay The stop time, relative to the current time. + * @return The stop EventId. */ - static void Stop(const Time& delay); + static EventId Stop(const Time& delay); + + /** + * Returns the Stop Event, or an invalid event if the simulation + * does not have a scheduled stop time. + * @return The stop EventId. + */ + static EventId GetStopEvent(); /** * Get the current simulation context. @@ -520,6 +528,11 @@ class Simulator */ static EventId DoScheduleDestroy(EventImpl* event); + /** + * Stop event (if present) + */ + static EventId m_stopEvent; + }; // class Simulator /** diff --git a/src/core/model/singleton.h b/src/core/model/singleton.h index 76512664b..a50e604ec 100644 --- a/src/core/model/singleton.h +++ b/src/core/model/singleton.h @@ -61,8 +61,8 @@ class Singleton { public: // Delete copy constructor and assignment operator to avoid misuse - Singleton(const Singleton&) = delete; - Singleton& operator=(const Singleton&) = delete; + Singleton(const Singleton&) = delete; + Singleton& operator=(const Singleton&) = delete; /** * Get a pointer to the singleton instance. @@ -76,12 +76,12 @@ class Singleton protected: /** Constructor. */ - Singleton() + Singleton() { } /** Destructor. */ - virtual ~Singleton() + virtual ~Singleton() { } }; diff --git a/src/core/model/type-id.cc b/src/core/model/type-id.cc index f1929df06..6ebe23380 100644 --- a/src/core/model/type-id.cc +++ b/src/core/model/type-id.cc @@ -383,7 +383,8 @@ IidManager::AllocateUid(std::string name) { NS_LOG_FUNCTION(IID << name); // Type names are definitive: equal names are equal types - NS_ASSERT_MSG(m_namemap.count(name) == 0, "Trying to allocate twice the same uid: " << name); + NS_ABORT_MSG_UNLESS(m_namemap.count(name) == 0, + "Trying to allocate twice the same uid: " << name); TypeId::hash_t hash = Hasher(name) & (~HashChainFlag); if (m_hashmap.count(hash) == 1) diff --git a/src/core/model/uniform-random-bit-generator.h b/src/core/model/uniform-random-bit-generator.h new file mode 100644 index 000000000..3e5a8803c --- /dev/null +++ b/src/core/model/uniform-random-bit-generator.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2023 Universita' degli Studi di Napoli Federico II + * + * 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: Stefano Avallone + */ +#ifndef UNIFORM_RANDOM_BIT_GENERATOR_H +#define UNIFORM_RANDOM_BIT_GENERATOR_H + +#include "random-variable-stream.h" + +#include + +namespace ns3 +{ + +/** + * Wraps a UniformRandomVariable into a class that meets the requirements of a + * UniformRandomBitGenerator as specified by the C++11 standard, thus allowing + * the usage of ns-3 style UniformRandomVariables as generators in the functions + * of the standard random library. + */ +class UniformRandomBitGenerator +{ + public: + UniformRandomBitGenerator() + : m_rv(CreateObject()) + { + } + + /** + * \return the ns-3 style uniform random variable + */ + Ptr GetRv() const + { + return m_rv; + } + + /// Typedef needed to meet requirements. Result type must be an unsigned integer type. + using result_type = uint32_t; + + /** + * \return the smallest value that operator() may return + */ + static constexpr result_type min() + { + return 0; + } + + /** + * \return the largest value that operator() may return + */ + static constexpr result_type max() + { + return std::numeric_limits::max(); + } + + /** + * \return a value in the closed interval [min(), max()] + */ + result_type operator()() + { + return m_rv->GetInteger(min(), max()); + } + + private: + Ptr m_rv; //!< ns-3 style uniform random variable +}; + +} // namespace ns3 + +#endif /* UNIFORM_RANDOM_BIT_GENERATOR_H */ diff --git a/src/core/model/unused.h b/src/core/model/unused.h deleted file mode 100644 index 9973f16aa..000000000 --- a/src/core/model/unused.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2012 Andrey Mazo - * - * 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: Andrey Mazo - */ - -#ifndef UNUSED_H -#define UNUSED_H - -#include "deprecated.h" - -/** - * \file - * \ingroup core - * NS_UNUSED and NS_UNUSED_GLOBAL macro definitions. - */ - -/** - * \ingroup core - * \def NS_UNUSED() - * Mark a local variable as unused. - * - * \deprecated Please use `[[maybe_unused]]` directly. This macro is being - * kept temporarily to support older code. - */ - -// We can't use NS_DEPRECATED_3_36 here because NS_UNUSED -// is used as a statement following a declaration: -// int x; -// NS_UNUSED (x); -// NS_DEPRECATED needs to be applied to the declaration -// NS_DEPRECATED_3_36 ("use double instead") int x; -// Instead we resort to a pragma - -#ifndef NS_UNUSED -#define NS_UNUSED(x) \ - _Pragma("GCC warning \"NS_UNUSED is deprecated, use [[maybe_unused]] directly\"")((void)(x)) -#endif - -/** - * \ingroup core - * \def NS_UNUSED_GLOBAL() - * Mark a variable at file scope as unused. - * - * \deprecated Please use `[[maybe_unused]]` directly. This macro is being - * kept temporarily to support older code. - */ -#ifndef NS_UNUSED_GLOBAL -#if defined(__GNUC__) -#define NS_UNUSED_GLOBAL(x) \ - NS_DEPRECATED_3_36("NS_UNUSED_GLOBAL is deprecated, use [[maybe_unused]] directly") \ - [[maybe_unused]] x -#elif defined(__LCLINT__) -#define NS_UNUSED_GLOBAL(x) \ - NS_DEPRECATED_3_36("NS_UNUSED_GLOBAL is deprecated, use [[maybe_unused]] directly") \ - /*@unused@*/ x -#else -#define NS_UNUSED_GLOBAL(x) \ - NS_DEPRECATED_3_36("NS_UNUSED_GLOBAL is deprecated, use [[maybe_unused]] directly") \ - x -#endif -#endif - -#endif /* UNUSED_H */ diff --git a/src/core/model/val-array.h b/src/core/model/val-array.h index c96b24c6a..9bd2ad968 100644 --- a/src/core/model/val-array.h +++ b/src/core/model/val-array.h @@ -80,7 +80,7 @@ class ValArray : public SimpleRefCount> { public: // instruct the compiler to generate the default constructor - ValArray() = default; + ValArray() = default; /** * \brief Constructor that creates "numPages" number of 2D arrays that are of * dimensions "numRows"x"numCols", and are initialized with all-zero elements. @@ -89,25 +89,25 @@ class ValArray : public SimpleRefCount> * \param numCols the number of columns * \param numPages the number of pages */ - ValArray(size_t numRows, size_t numCols = 1, size_t numPages = 1); + ValArray(size_t numRows, size_t numCols = 1, size_t numPages = 1); /** * \brief Constructor creates a single 1D array of values.size () elements and 1 column, * and uses std::valarray values to initialize the elements. * \param values std::valarray that will be used to initialize elements of 1D array */ - explicit ValArray(const std::valarray& values); + explicit ValArray(const std::valarray& values); /** * \brief Constructor creates a single 1D array of values.size () elements and 1 column, * and moves std::valarray values to initialize the elements. * \param values std::valarray that will be moved to initialize elements of 1D array */ - ValArray(std::valarray&& values); + ValArray(std::valarray&& values); /** * \brief Constructor creates a single 1D array of values.size () elements and 1 column, * and uses values std::vector to initialize the elements. * \param values std::vector that will be used to initialize elements of 1D array */ - explicit ValArray(const std::vector& values); + explicit ValArray(const std::vector& values); /** * \brief Constructor creates a single 2D array of numRows and numCols, and uses * std::valarray values to initialize the elements. @@ -115,7 +115,7 @@ class ValArray : public SimpleRefCount> * \param numCols the number of columns * \param values valarray that will be used to initialize elements of 3D array */ - ValArray(size_t numRows, size_t numCols, const std::valarray& values); + ValArray(size_t numRows, size_t numCols, const std::valarray& values); /** * \brief Constructor creates a single 2D array of numRows and numCols, and moves * std::valarray values to initialize the elements. @@ -123,7 +123,7 @@ class ValArray : public SimpleRefCount> * \param numCols the number of columns * \param values valarray that will be used to initialize elements of 3D array */ - ValArray(size_t numRows, size_t numCols, std::valarray&& values); + ValArray(size_t numRows, size_t numCols, std::valarray&& values); /** * \brief Constructor creates the 3D array of numRows x numCols x numPages dimensions, * and uses std::valarray values to initialize all the 2D arrays, where first @@ -133,7 +133,7 @@ class ValArray : public SimpleRefCount> * \param numPages the number of pages * \param values valarray that will be used to initialize elements of 3D array */ - ValArray(size_t numRows, size_t numCols, size_t numPages, const std::valarray& values); + ValArray(size_t numRows, size_t numCols, size_t numPages, const std::valarray& values); /** * \brief Constructor creates the 3D array of numRows x numCols x numPages dimensions, * and moves std::valarray values to initialize all the 2D arrays, where first @@ -143,19 +143,19 @@ class ValArray : public SimpleRefCount> * \param numPages the number of pages * \param values valarray that will be used to initialize elements of 3D array */ - ValArray(size_t numRows, size_t numCols, size_t numPages, std::valarray&& values); + ValArray(size_t numRows, size_t numCols, size_t numPages, std::valarray&& values); /** instruct the compiler to generate the implicitly declared destructor*/ - virtual ~ValArray() = default; + virtual ~ValArray() = default; /** instruct the compiler to generate the implicitly declared copy constructor*/ - ValArray(const ValArray&) = default; + ValArray(const ValArray&) = default; /** * \brief Copy assignment operator. * Instruct the compiler to generate the implicitly declared copy assignment operator. * \return a reference to the assigned object */ - ValArray& operator=(const ValArray&) = default; + ValArray& operator=(const ValArray&) = default; /** instruct the compiler to generate the implicitly declared move constructor*/ - ValArray(ValArray&&) = default; + ValArray(ValArray&&) = default; /** * \brief Move assignment operator. * Instruct the compiler to generate the implicitly declared move assignment operator. @@ -240,24 +240,24 @@ class ValArray : public SimpleRefCount> * \returns ValArray in which each element has been multiplied by the given * scalar value. */ - ValArray operator*(const T& rhs) const; + ValArray operator*(const T& rhs) const; /** * \brief operator+ definition for ValArray. * \param rhs The rhs ValArray to be added to this ValArray. * \return the ValArray instance that holds the results of the operator+ */ - ValArray operator+(const ValArray& rhs) const; + ValArray operator+(const ValArray& rhs) const; /** * \brief binary operator- definition for ValArray. * \param rhs The rhs ValArray to be subtracted from this ValArray. * \return the ValArray instance that holds the results of the operator- */ - ValArray operator-(const ValArray& rhs) const; + ValArray operator-(const ValArray& rhs) const; /** * \brief unary operator- definition for ValArray. * \return the ValArray instance that holds the results of the operator- */ - ValArray operator-() const; + ValArray operator-() const; /** * \brief operator+= definition for ValArray. * \param rhs The rhs ValArray to be added to this ValArray. @@ -379,21 +379,21 @@ inline size_t ValArray::GetNumRows() const { return m_numRows; -}; +} template inline size_t ValArray::GetNumCols() const { return m_numCols; -}; +} template inline size_t ValArray::GetNumPages() const { return m_numPages; -}; +} template inline size_t @@ -411,7 +411,7 @@ ValArray::operator()(size_t rowIndex, size_t colIndex, size_t pageIndex) NS_ASSERT_MSG(pageIndex < m_numPages, "Pages index out of bounds"); size_t index = (rowIndex + m_numRows * (colIndex + m_numCols * pageIndex)); return m_values[index]; -}; +} template inline const T& @@ -422,7 +422,7 @@ ValArray::operator()(size_t rowIndex, size_t colIndex, size_t pageIndex) cons NS_ASSERT_MSG(pageIndex < m_numPages, "Pages index out of bounds"); size_t index = (rowIndex + m_numRows * (colIndex + m_numCols * pageIndex)); return m_values[index]; -}; +} template inline T& @@ -430,7 +430,7 @@ ValArray::operator()(size_t rowIndex, size_t colIndex) { NS_ASSERT_MSG(m_numPages == 1, "Cannot use 2D access operator for 3D ValArray."); return (*this)(rowIndex, colIndex, 0); -}; +} template inline const T& @@ -438,7 +438,7 @@ ValArray::operator()(size_t rowIndex, size_t colIndex) const { NS_ASSERT_MSG(m_numPages == 1, "Cannot use 2D access operator for 3D ValArray."); return (*this)(rowIndex, colIndex, 0); -}; +} template inline T& @@ -451,7 +451,7 @@ ValArray::operator()(size_t index) (m_numRows == 1 && m_numCols == 1), "Access operator allowed only for 1D ValArray."); return m_values[index]; -}; +} template inline const T& @@ -464,7 +464,7 @@ ValArray::operator()(size_t index) const (m_numRows == 1 && m_numCols == 1), "Access operator allowed only for 1D ValArray."); return m_values[index]; -}; +} template inline ValArray @@ -523,7 +523,7 @@ ValArray::GetPagePtr(size_t pageIndex) { NS_ASSERT_MSG(pageIndex < m_numPages, "Invalid page index."); return &(m_values[m_numRows * m_numCols * pageIndex]); -}; +} template inline const T* @@ -531,7 +531,7 @@ ValArray::GetPagePtr(size_t pageIndex) const { NS_ASSERT_MSG(pageIndex < m_numPages, "Invalid page index."); return &(m_values[m_numRows * m_numCols * pageIndex]); -}; +} template inline bool @@ -567,14 +567,14 @@ inline T& ValArray::Elem(size_t row, size_t col, size_t page) { return (*this)(row, col, page); -}; +} template inline const T& ValArray::Elem(size_t row, size_t col, size_t page) const { return (*this)(row, col, page); -}; +} /************************************************* ** Class ValArray non-inline implementations @@ -587,7 +587,7 @@ ValArray::ValArray(size_t numRows, size_t numCols, size_t numPages) m_numPages{numPages} { m_values.resize(m_numRows * m_numCols * m_numPages); -}; +} template ValArray::ValArray(const std::valarray& values) @@ -626,7 +626,7 @@ ValArray::ValArray(size_t numRows, size_t numCols, const std::valarray& va { NS_ASSERT_MSG(m_numRows * m_numCols == values.size(), "Dimensions and the initialization array size do not match."); -}; +} template ValArray::ValArray(size_t numRows, size_t numCols, std::valarray&& values) @@ -637,7 +637,7 @@ ValArray::ValArray(size_t numRows, size_t numCols, std::valarray&& values) NS_ASSERT_MSG(m_numRows * m_numCols == values.size(), "Dimensions and the initialization array size do not match."); m_values = std::move(values); -}; +} template ValArray::ValArray(size_t numRows, @@ -651,7 +651,7 @@ ValArray::ValArray(size_t numRows, { NS_ASSERT_MSG(m_numRows * m_numCols * m_numPages == values.size(), "Dimensions and the initialization array size do not match."); -}; +} template ValArray::ValArray(size_t numRows, size_t numCols, size_t numPages, std::valarray&& values) @@ -662,7 +662,7 @@ ValArray::ValArray(size_t numRows, size_t numCols, size_t numPages, std::vala NS_ASSERT_MSG(m_numRows * m_numCols * m_numPages == values.size(), "Dimensions and the initialization array size do not match."); m_values = std::move(values); -}; +} template bool diff --git a/src/core/model/wall-clock-synchronizer.cc b/src/core/model/wall-clock-synchronizer.cc index 0f1d386f7..f11b84ee2 100644 --- a/src/core/model/wall-clock-synchronizer.cc +++ b/src/core/model/wall-clock-synchronizer.cc @@ -128,7 +128,7 @@ WallClockSynchronizer::DoGetDrift(uint64_t ns) // then subtract the current real time in normalized nanoseconds we just got // from the normalized simulation time in nanoseconds that is passed in as // the parameter ns. We return an integer difference, but in reality all of - // the mechanisms that cause wall-clock to simuator time drift cause events + // the mechanisms that cause wall-clock to simulator time drift cause events // to be late. That means that the wall-clock will be higher than the // simulation time and drift will be positive. I would be astonished to // see a negative drift, but the possibility is admitted for other diff --git a/src/core/test/attribute-test-suite.cc b/src/core/test/attribute-test-suite.cc index a2f156541..9dac00d32 100644 --- a/src/core/test/attribute-test-suite.cc +++ b/src/core/test/attribute-test-suite.cc @@ -157,6 +157,14 @@ class AttributeObjectTest : public Object TEST_C //!< Test value C. }; + /// Test enumerator. + enum class Test_ec + { + TEST_D, //!< Test value D. + TEST_E, //!< Test value E. + TEST_F //!< Test value F. + }; + /** * \brief Get the type ID. * \return The object TypeId. @@ -203,14 +211,35 @@ class AttributeObjectTest : public Object .AddAttribute("TestEnum", "help text", EnumValue(TEST_A), - MakeEnumAccessor(&AttributeObjectTest::m_enum), + MakeEnumAccessor(&AttributeObjectTest::m_enum), MakeEnumChecker(TEST_A, "TestA", TEST_B, "TestB", TEST_C, "TestC")) .AddAttribute("TestEnumSetGet", "help text", EnumValue(TEST_B), - MakeEnumAccessor(&AttributeObjectTest::DoSetEnum, - &AttributeObjectTest::DoGetEnum), + MakeEnumAccessor(&AttributeObjectTest::DoSetEnum, + &AttributeObjectTest::DoGetEnum), MakeEnumChecker(TEST_A, "TestA", TEST_B, "TestB", TEST_C, "TestC")) + .AddAttribute("TestEnumClass", + "help text", + EnumValue(Test_ec::TEST_D), + MakeEnumAccessor(&AttributeObjectTest::m_enumclass), + MakeEnumChecker(Test_ec::TEST_D, + "TestD", + Test_ec::TEST_E, + "TestE", + Test_ec::TEST_F, + "TestF")) + .AddAttribute("TestEnumClassSetGet", + "help text", + EnumValue(Test_ec::TEST_E), + MakeEnumAccessor(&AttributeObjectTest::DoSetEnumClass, + &AttributeObjectTest::DoGetEnumClass), + MakeEnumChecker(Test_ec::TEST_D, + "TestD", + Test_ec::TEST_E, + "TestE", + Test_ec::TEST_F, + "TestF")) .AddAttribute("TestRandom", "help text", StringValue("ns3::ConstantRandomVariable[Constant=1.0]"), @@ -268,11 +297,12 @@ class AttributeObjectTest : public Object BooleanValue(false), MakeBooleanAccessor(&AttributeObjectTest::m_boolSrc), MakeBooleanChecker()) - .AddAttribute("EnumTraceSource", - "help text", - EnumValue(TEST_A), - MakeEnumAccessor(&AttributeObjectTest::m_enumSrc), - MakeEnumChecker(TEST_A, "TestA")) + .AddAttribute( + "EnumTraceSource", + "help text", + EnumValue(TEST_A), + MakeEnumAccessor>(&AttributeObjectTest::m_enumSrc), + MakeEnumChecker(TEST_A, "TestA")) .AddAttribute("ValueClassSource", "help text", ValueClassTestValue(ValueClassTest()), @@ -492,6 +522,26 @@ class AttributeObjectTest : public Object return m_enumSetGet; } + /** + * Set the m_enumClassSetGet value. + * \param v The value to set. + * \return true. + */ + bool DoSetEnumClass(Test_ec v) + { + m_enumClassSetGet = v; + return true; + } + + /** + * Get the m_enumClassSetGet value. + * \return the value of m_enumSetGet. + */ + Test_ec DoGetEnumClass() const + { + return m_enumClassSetGet; + } + bool m_boolTestA; //!< Boolean test A. bool m_boolTest; //!< Boolean test. bool m_boolTestDeprecated; //!< Boolean test deprecated. @@ -502,6 +552,8 @@ class AttributeObjectTest : public Object float m_float; //!< float. Test_e m_enum; //!< Enum. Test_e m_enumSetGet; //!< Enum set-get. + Test_ec m_enumclass; //!< Enum class. + Test_ec m_enumClassSetGet; //!< Enum class set-get. Ptr m_random; //!< Random number generator. std::vector> m_vector1; //!< First vector of derived objects. std::vector> m_vector2; //!< Second vector of derived objects. @@ -604,10 +656,7 @@ template <> void AttributeTestCase::DoRun() { - Ptr p; - bool ok; - - p = CreateObject(); + auto p = CreateObject(); NS_TEST_ASSERT_MSG_NE(p, nullptr, "Unable to CreateObject"); // @@ -618,7 +667,7 @@ AttributeTestCase::DoRun() p = CreateObject(); NS_TEST_ASSERT_MSG_NE(p, nullptr, "Unable to CreateObject"); - ok = CheckGetCodePaths(p, "TestBoolName", "true", BooleanValue(true)); + bool ok = CheckGetCodePaths(p, "TestBoolName", "true", BooleanValue(true)); NS_TEST_ASSERT_MSG_EQ(ok, true, "Attribute not set properly by default value"); std::string expected("Attribute 'TestDeprecated' is deprecated: DEPRECATED test working.\n"); @@ -705,17 +754,14 @@ template <> void AttributeTestCase::DoRun() { - Ptr p; - bool ok; - - p = CreateObject(); + auto p = CreateObject(); NS_TEST_ASSERT_MSG_NE(p, nullptr, "Unable to CreateObject"); // // When the object is first created, the Attribute should have the default // value. // - ok = CheckGetCodePaths(p, "TestInt16", "-2", IntegerValue(-2)); + bool ok = CheckGetCodePaths(p, "TestInt16", "-2", IntegerValue(-2)); NS_TEST_ASSERT_MSG_EQ(ok, true, "Attribute not set properly by default value"); // @@ -840,17 +886,14 @@ template <> void AttributeTestCase::DoRun() { - Ptr p; - bool ok; - - p = CreateObject(); + auto p = CreateObject(); NS_TEST_ASSERT_MSG_NE(p, nullptr, "Unable to CreateObject"); // // When the object is first created, the Attribute should have the default // value. // - ok = CheckGetCodePaths(p, "TestUint8", "1", UintegerValue(1)); + bool ok = CheckGetCodePaths(p, "TestUint8", "1", UintegerValue(1)); NS_TEST_ASSERT_MSG_EQ(ok, true, "Attribute not set properly by default value"); // @@ -923,17 +966,14 @@ template <> void AttributeTestCase::DoRun() { - Ptr p; - bool ok; - - p = CreateObject(); + auto p = CreateObject(); NS_TEST_ASSERT_MSG_NE(p, nullptr, "Unable to CreateObject"); // // When the object is first created, the Attribute should have the default // value. // - ok = CheckGetCodePaths(p, "TestFloat", "-1.1", DoubleValue(-1.1F)); + bool ok = CheckGetCodePaths(p, "TestFloat", "-1.1", DoubleValue(-1.1F)); NS_TEST_ASSERT_MSG_EQ(ok, true, "Attribute not set properly by default value"); // @@ -950,19 +990,16 @@ AttributeTestCase::DoRun() template <> void -AttributeTestCase::DoRun() +AttributeTestCase>::DoRun() { - Ptr p; - bool ok; - - p = CreateObject(); + auto p = CreateObject(); NS_TEST_ASSERT_MSG_NE(p, nullptr, "Unable to CreateObject"); // // When the object is first created, the Attribute should have the default // value. // - ok = CheckGetCodePaths(p, "TestEnum", "TestA", EnumValue(AttributeObjectTest::TEST_A)); + bool ok = CheckGetCodePaths(p, "TestEnum", "TestA", EnumValue(AttributeObjectTest::TEST_A)); NS_TEST_ASSERT_MSG_EQ(ok, true, "Attribute not set properly by default value"); // @@ -1026,14 +1063,108 @@ AttributeTestCase::DoRun() NS_TEST_ASSERT_MSG_EQ(ok, true, "Error in SetAttributeFailSafe() but value changes"); } +template <> +void +AttributeTestCase>::DoRun() +{ + auto p = CreateObject(); + NS_TEST_ASSERT_MSG_NE(p, nullptr, "Unable to CreateObject"); + + // + // When the object is first created, the Attribute should have the default + // value. + // + bool ok = CheckGetCodePaths(p, + "TestEnumClass", + "TestD", + EnumValue(AttributeObjectTest::Test_ec::TEST_D)); + NS_TEST_ASSERT_MSG_EQ(ok, true, "Attribute not set properly by default value"); + + // + // Set the Attribute using the EnumValue type. + // + ok = p->SetAttributeFailSafe("TestEnumClass", EnumValue(AttributeObjectTest::Test_ec::TEST_F)); + NS_TEST_ASSERT_MSG_EQ(ok, true, "Could not SetAttributeFailSafe() to TEST_F"); + + ok = CheckGetCodePaths(p, + "TestEnumClass", + "TestF", + EnumValue(AttributeObjectTest::Test_ec::TEST_F)); + NS_TEST_ASSERT_MSG_EQ(ok, + true, + "Attribute not set properly by SetAttributeFailSafe() via EnumValue"); + + // + // When the object is first created, the Attribute should have the default + // value. + // + ok = CheckGetCodePaths(p, + "TestEnumClassSetGet", + "TestE", + EnumValue(AttributeObjectTest::Test_ec::TEST_E)); + NS_TEST_ASSERT_MSG_EQ(ok, true, "Attribute not set properly by default value"); + + // + // Set the Attribute using the EnumValue type. + // + ok = p->SetAttributeFailSafe("TestEnumClassSetGet", + EnumValue(AttributeObjectTest::Test_ec::TEST_F)); + NS_TEST_ASSERT_MSG_EQ(ok, true, "Could not SetAttributeFailSafe() to TEST_F"); + + ok = CheckGetCodePaths(p, + "TestEnumClassSetGet", + "TestF", + EnumValue(AttributeObjectTest::Test_ec::TEST_F)); + NS_TEST_ASSERT_MSG_EQ(ok, + true, + "Attribute not set properly by SetAttributeFailSafe() via EnumValue"); + + // + // Set the Attribute using the StringValue type. + // + ok = p->SetAttributeFailSafe("TestEnumClass", StringValue("TestE")); + NS_TEST_ASSERT_MSG_EQ(ok, true, "Could not SetAttributeFailSafe() to TEST_E"); + + ok = CheckGetCodePaths(p, + "TestEnumClass", + "TestE", + EnumValue(AttributeObjectTest::Test_ec::TEST_E)); + NS_TEST_ASSERT_MSG_EQ(ok, + true, + "Attribute not set properly by SetAttributeFailSafe() via StringValue"); + + // + // Try to set the Attribute to a bogus enum using the StringValue type + // throws a fatal error. + // + // ok = p->SetAttributeFailSafe ("TestEnumClass", StringValue ("TestG")); + // NS_TEST_ASSERT_MSG_EQ (ok, false, "Unexpectedly could SetAttributeFailSafe() to TEST_G"); // + + ok = CheckGetCodePaths(p, + "TestEnumClass", + "TestE", + EnumValue(AttributeObjectTest::Test_ec::TEST_E)); + NS_TEST_ASSERT_MSG_EQ(ok, true, "Error in SetAttributeFailSafe() but value changes"); + + // + // Try to set the Attribute to a bogus enum using an integer implicit conversion + // and make sure the underlying value doesn't change. + // + ok = p->SetAttributeFailSafe("TestEnumClass", EnumValue(5)); + NS_TEST_ASSERT_MSG_EQ(ok, false, "Unexpectedly could SetAttributeFailSafe() to 5"); + + ok = CheckGetCodePaths(p, + "TestEnumClass", + "TestE", + EnumValue(AttributeObjectTest::Test_ec::TEST_E)); + NS_TEST_ASSERT_MSG_EQ(ok, true, "Error in SetAttributeFailSafe() but value changes"); +} + template <> void AttributeTestCase::DoRun() { - Ptr p; - bool ok; - - p = CreateObject(); + auto p = CreateObject(); NS_TEST_ASSERT_MSG_NE(p, nullptr, "Unable to CreateObject"); // The test vectors assume ns resolution @@ -1042,7 +1173,7 @@ AttributeTestCase::DoRun() // // Set value // - ok = p->SetAttributeFailSafe("TestTimeWithBounds", TimeValue(Seconds(5))); + bool ok = p->SetAttributeFailSafe("TestTimeWithBounds", TimeValue(Seconds(5))); NS_TEST_ASSERT_MSG_EQ(ok, true, "Could not SetAttributeFailSafe() via TimeValue to 5s"); ok = CheckGetCodePaths(p, "TestTimeWithBounds", "+5e+09ns", TimeValue(Seconds(5))); @@ -1168,17 +1299,14 @@ RandomVariableStreamAttributeTestCase::RandomVariableStreamAttributeTestCase( void RandomVariableStreamAttributeTestCase::DoRun() { - Ptr p; - bool ok; - - p = CreateObject(); + auto p = CreateObject(); NS_TEST_ASSERT_MSG_NE(p, nullptr, "Unable to CreateObject"); // // Try to set a UniformRandomVariable // - ok = p->SetAttributeFailSafe("TestRandom", - StringValue("ns3::UniformRandomVariable[Min=0.|Max=1.]")); + bool ok = p->SetAttributeFailSafe("TestRandom", + StringValue("ns3::UniformRandomVariable[Min=0.|Max=1.]")); NS_TEST_ASSERT_MSG_EQ(ok, true, "Could not SetAttributeFailSafe() a UniformRandomVariable"); // @@ -1221,10 +1349,9 @@ ObjectVectorAttributeTestCase::ObjectVectorAttributeTestCase(std::string descrip void ObjectVectorAttributeTestCase::DoRun() { - Ptr p; ObjectVectorValue vector; - p = CreateObject(); + auto p = CreateObject(); NS_TEST_ASSERT_MSG_NE(p, nullptr, "Unable to CreateObject"); // @@ -1306,10 +1433,9 @@ ObjectMapAttributeTestCase::ObjectMapAttributeTestCase(std::string description) void ObjectMapAttributeTestCase::DoRun() { - Ptr p; ObjectMapValue map; - p = CreateObject(); + auto p = CreateObject(); NS_TEST_ASSERT_MSG_NE(p, nullptr, "Unable to CreateObject"); // @@ -1423,11 +1549,9 @@ IntegerTraceSourceAttributeTestCase::IntegerTraceSourceAttributeTestCase(std::st void IntegerTraceSourceAttributeTestCase::DoRun() { - Ptr p; IntegerValue iv; - bool ok; - p = CreateObject(); + auto p = CreateObject(); NS_TEST_ASSERT_MSG_NE(p, nullptr, "Unable to CreateObject"); // @@ -1440,7 +1564,7 @@ IntegerTraceSourceAttributeTestCase::DoRun() // // Set the Attribute to a positive value through an IntegerValue. // - ok = p->SetAttributeFailSafe("IntegerTraceSource1", IntegerValue(5)); + bool ok = p->SetAttributeFailSafe("IntegerTraceSource1", IntegerValue(5)); NS_TEST_ASSERT_MSG_EQ(ok, true, "Could not SetAttributeFailSafe() via IntegerValue to 5"); p->GetAttribute("IntegerTraceSource1", iv); @@ -1548,10 +1672,7 @@ IntegerTraceSourceTestCase::IntegerTraceSourceTestCase(std::string description) void IntegerTraceSourceTestCase::DoRun() { - Ptr p; - bool ok; - - p = CreateObject(); + auto p = CreateObject(); NS_TEST_ASSERT_MSG_NE(p, nullptr, "Unable to CreateObject"); // @@ -1560,7 +1681,7 @@ IntegerTraceSourceTestCase::DoRun() // m_got1 = 1234; - ok = p->SetAttributeFailSafe("IntegerTraceSource1", IntegerValue(-1)); + bool ok = p->SetAttributeFailSafe("IntegerTraceSource1", IntegerValue(-1)); NS_TEST_ASSERT_MSG_EQ(ok, true, "Could not SetAttributeFailSafe() via IntegerValue to -1"); // @@ -1651,10 +1772,7 @@ TracedCallbackTestCase::TracedCallbackTestCase(std::string description) void TracedCallbackTestCase::DoRun() { - Ptr p; - bool ok; - - p = CreateObject(); + auto p = CreateObject(); NS_TEST_ASSERT_MSG_NE(p, nullptr, "Unable to CreateObject"); // @@ -1680,8 +1798,9 @@ TracedCallbackTestCase::DoRun() // Now, wire the TracedCallback up to a trace sink. This sink will just set // m_got2 to the first argument. // - ok = p->TraceConnectWithoutContext("Source2", - MakeCallback(&TracedCallbackTestCase::NotifySource2, this)); + bool ok = + p->TraceConnectWithoutContext("Source2", + MakeCallback(&TracedCallbackTestCase::NotifySource2, this)); NS_TEST_ASSERT_MSG_EQ(ok, true, "Could not TraceConnectWithoutContext() to NotifySource2"); // @@ -1752,10 +1871,7 @@ PointerAttributeTestCase::PointerAttributeTestCase(std::string description) void PointerAttributeTestCase::DoRun() { - Ptr p; - bool ok; - - p = CreateObject(); + auto p = CreateObject(); NS_TEST_ASSERT_MSG_NE(p, nullptr, "Unable to CreateObject"); // @@ -1776,7 +1892,7 @@ PointerAttributeTestCase::DoRun() // to that object. We can then set the PointerValue Attribute to that Ptr. // derived = Create(); - ok = p->SetAttributeFailSafe("Pointer", PointerValue(derived)); + bool ok = p->SetAttributeFailSafe("Pointer", PointerValue(derived)); NS_TEST_ASSERT_MSG_EQ(ok, true, "Could not SetAttributeFailSafe() a PointerValue of the correct type"); @@ -1910,10 +2026,7 @@ CallbackValueTestCase::CallbackValueTestCase(std::string description) void CallbackValueTestCase::DoRun() { - Ptr p; - bool ok; - - p = CreateObject(); + auto p = CreateObject(); NS_TEST_ASSERT_MSG_NE(p, nullptr, "Unable to CreateObject"); // @@ -1938,7 +2051,7 @@ CallbackValueTestCase::DoRun() NS_TEST_ASSERT_MSG_EQ(m_gotCbValue, 1, "Callback unexpectedly fired"); - ok = p->SetAttributeFailSafe("Callback", cbValue); + bool ok = p->SetAttributeFailSafe("Callback", cbValue); NS_TEST_ASSERT_MSG_EQ(ok, true, "Could not SetAttributeFailSafe() a CallbackValue"); // @@ -1981,7 +2094,11 @@ AttributesTestSuite::AttributesTestSuite() TestCase::QUICK); AddTestCase(new AttributeTestCase("Check Attributes of type DoubleValue"), TestCase::QUICK); - AddTestCase(new AttributeTestCase("Check Attributes of type EnumValue"), + AddTestCase(new AttributeTestCase>( + "Check Attributes of type EnumValue"), + TestCase::QUICK); + AddTestCase(new AttributeTestCase>( + "Check Attributes of type EnumValue (wrapping an enum class)"), TestCase::QUICK); AddTestCase(new AttributeTestCase("Check Attributes of type TimeValue"), TestCase::QUICK); diff --git a/src/core/test/int64x64-test-suite.cc b/src/core/test/int64x64-test-suite.cc index cf9933bb8..dd691477e 100644 --- a/src/core/test/int64x64-test-suite.cc +++ b/src/core/test/int64x64-test-suite.cc @@ -485,7 +485,7 @@ Int64x64ArithmeticTestCase::DoRun() const int64x64_t zero(0, 0); const int64x64_t one(1, 0); const int64x64_t two(2, 0); - const int64x64_t thre(3, 0); + const int64x64_t three(3, 0); std::cout << std::endl; std::cout << GetParent()->GetName() << " Arithmetic: " << GetName() << std::endl; @@ -497,14 +497,14 @@ Int64x64ArithmeticTestCase::DoRun() Check(3, one - two, -one); Check(4, one - (-one), two); Check(5, (-one) - (-two), one); - Check(6, (-one) - two, -thre); + Check(6, (-one) - two, -three); Check(7, zero + zero, zero); Check(8, zero + one, one); Check(9, one + one, two); - Check(10, one + two, thre); + Check(10, one + two, three); Check(11, one + (-one), zero); - Check(12, (-one) + (-two), -thre); + Check(12, (-one) + (-two), -three); Check(13, (-one) + two, one); Check(14, zero * zero, zero); @@ -514,7 +514,7 @@ Int64x64ArithmeticTestCase::DoRun() Check(18, one * (-one), -one); Check(19, (-one) * (-one), one); - Check(20, (two * thre) / thre, two); + Check(20, (two * three) / three, two); // NOLINTEND(misc-redundant-expression) const int64x64_t frac = int64x64_t(0, 0xc000000000000000ULL); // 0.75 @@ -526,7 +526,7 @@ Int64x64ArithmeticTestCase::DoRun() const int64x64_t zerof = zero + frac; const int64x64_t onef = one + frac; const int64x64_t twof = two + frac; - const int64x64_t thref = thre + frac; + const int64x64_t thref = three + frac; // NOLINTBEGIN(misc-redundant-expression) Check(23, zerof, frac); @@ -559,11 +559,11 @@ Int64x64ArithmeticTestCase::DoRun() // NOLINTEND(misc-redundant-expression) // Multiplication followed by division is exact: - Check(46, (two * thre) / thre, two); + Check(46, (two * three) / three, two); Check(47, (twof * thref) / thref, twof); // Division followed by multiplication loses a bit or two: - Check(48, (two / thre) * thre, two, 2 * tol1); + Check(48, (two / three) * three, two, 2 * tol1); Check(49, (twof / thref) * thref, twof, 3 * tol1); // The example below shows that we really do not lose diff --git a/src/core/test/matrix-array-test-suite.cc b/src/core/test/matrix-array-test-suite.cc index 595932b6d..574fe4dd7 100644 --- a/src/core/test/matrix-array-test-suite.cc +++ b/src/core/test/matrix-array-test-suite.cc @@ -44,21 +44,21 @@ template class MatrixArrayTestCase : public TestCase { public: - MatrixArrayTestCase() = default; + MatrixArrayTestCase() = default; /** * Constructor * * \param [in] name reference name */ - MatrixArrayTestCase(const std::string& name); + MatrixArrayTestCase(const std::string& name); /** Destructor. */ - ~MatrixArrayTestCase() override; + ~MatrixArrayTestCase() override; /** * \brief Copy constructor. * Instruct the compiler to generate the implicitly declared copy constructor */ - MatrixArrayTestCase(const MatrixArrayTestCase&) = default; + MatrixArrayTestCase(const MatrixArrayTestCase&) = default; /** * \brief Copy assignment operator. * Instruct the compiler to generate the implicitly declared copy assignment operator. @@ -69,7 +69,7 @@ class MatrixArrayTestCase : public TestCase * \brief Move constructor. * Instruct the compiler to generate the implicitly declared move constructor */ - MatrixArrayTestCase(MatrixArrayTestCase&&) = default; + MatrixArrayTestCase(MatrixArrayTestCase&&) = default; /** * \brief Move assignment operator. * Instruct the compiler to generate the implicitly declared copy constructor @@ -89,7 +89,7 @@ MatrixArrayTestCase::MatrixArrayTestCase(const std::string& name) } template -MatrixArrayTestCase::~MatrixArrayTestCase() +MatrixArrayTestCase::~MatrixArrayTestCase() { } diff --git a/src/core/test/random-variable-stream-test-suite.cc b/src/core/test/random-variable-stream-test-suite.cc index d9e7c3d0a..f91e50a6d 100644 --- a/src/core/test/random-variable-stream-test-suite.cc +++ b/src/core/test/random-variable-stream-test-suite.cc @@ -34,6 +34,7 @@ #include #include #include +#include #include using namespace ns3; @@ -2565,6 +2566,312 @@ NormalCachingTestCase::DoRun() NS_TEST_ASSERT_MSG_GT(v2, 0, "Incorrect value returned, expected > 0"); } +/** + * \ingroup rng-tests + * Test case for bernoulli distribution random variable stream generator + */ +class BernoulliTestCase : public TestCaseBase +{ + public: + // Constructor + BernoulliTestCase(); + + // Inherited + double ChiSquaredTest(Ptr rng) const override; + + private: + // Inherited + void DoRun() override; + + /** Tolerance for testing rng values against expectation, in rms. */ + static constexpr double TOLERANCE{5}; +}; + +BernoulliTestCase::BernoulliTestCase() + : TestCaseBase("Bernoulli Random Variable Stream Generator") +{ +} + +double +BernoulliTestCase::ChiSquaredTest(Ptr rng) const +{ + gsl_histogram* h = gsl_histogram_alloc(2); + auto range = UniformHistogramBins(h, 0, 1); + + double p = 0.5; + std::vector expected = {N_MEASUREMENTS * (1 - p), N_MEASUREMENTS * p}; + + double chiSquared = ChiSquared(h, expected, rng); + + gsl_histogram_free(h); + return chiSquared; +} + +void +BernoulliTestCase::DoRun() +{ + NS_LOG_FUNCTION(this); + SetTestSuiteSeed(); + + auto generator = RngGenerator(); + double sum = ChiSquaredsAverage(&generator, N_RUNS); + double maxStatistic = gsl_cdf_chisq_Qinv(0.05, 1); + NS_TEST_ASSERT_MSG_LT(sum, maxStatistic, "Chi-squared statistic out of range"); + + double probability = 0.5; + + // Create the RNG with the specified range. + Ptr x = CreateObject(); + x->SetAttribute("Probability", DoubleValue(probability)); + + // Calculate the mean of these values. + double mean = probability; + double valueMean = Average(x); + double expectedMean = mean; + double expectedRms = std::sqrt(mean / N_MEASUREMENTS); + + // Test that values have approximately the right mean value. + NS_TEST_ASSERT_MSG_EQ_TOL(valueMean, + expectedMean, + expectedRms * TOLERANCE, + "Wrong mean value."); +} + +/** + * \ingroup rng-tests + * Test case for antithetic bernoulli distribution random variable stream generator + */ +class BernoulliAntitheticTestCase : public TestCaseBase +{ + public: + // Constructor + BernoulliAntitheticTestCase(); + + // Inherited + double ChiSquaredTest(Ptr rng) const override; + + private: + // Inherited + void DoRun() override; + + /** Tolerance for testing rng values against expectation, in rms. */ + static constexpr double TOLERANCE{5}; +}; + +BernoulliAntitheticTestCase::BernoulliAntitheticTestCase() + : TestCaseBase("Antithetic Bernoulli Random Variable Stream Generator") +{ +} + +double +BernoulliAntitheticTestCase::ChiSquaredTest(Ptr rng) const +{ + gsl_histogram* h = gsl_histogram_alloc(2); + auto range = UniformHistogramBins(h, 0, 1); + + double p = 0.5; + std::vector expected = {N_MEASUREMENTS * (1 - p), N_MEASUREMENTS * p}; + + double chiSquared = ChiSquared(h, expected, rng); + + gsl_histogram_free(h); + return chiSquared; +} + +void +BernoulliAntitheticTestCase::DoRun() +{ + NS_LOG_FUNCTION(this); + SetTestSuiteSeed(); + + auto generator = RngGenerator(true); + double sum = ChiSquaredsAverage(&generator, N_RUNS); + double maxStatistic = gsl_cdf_chisq_Qinv(0.05, 1); + NS_TEST_ASSERT_MSG_LT(sum, maxStatistic, "Chi-squared statistic out of range"); + + double probability = 0.5; + + // Create the RNG with the specified range. + Ptr x = CreateObject(); + x->SetAttribute("Probability", DoubleValue(probability)); + + // Make this generate antithetic values. + x->SetAttribute("Antithetic", BooleanValue(true)); + + // Calculate the mean of these values. + double mean = probability; + double valueMean = Average(x); + double expectedMean = mean; + double expectedRms = std::sqrt(mean / N_MEASUREMENTS); + + // Test that values have approximately the right mean value. + NS_TEST_ASSERT_MSG_EQ_TOL(valueMean, + expectedMean, + expectedRms * TOLERANCE, + "Wrong mean value."); +} + +/** + * \ingroup rng-tests + * Test case for binomial distribution random variable stream generator + */ +class BinomialTestCase : public TestCaseBase +{ + public: + // Constructor + BinomialTestCase(); + + // Inherited + double ChiSquaredTest(Ptr rng) const override; + + private: + // Inherited + void DoRun() override; + + /** Tolerance for testing rng values against expectation, in rms. */ + static constexpr double TOLERANCE{5}; +}; + +BinomialTestCase::BinomialTestCase() + : TestCaseBase("Binomial Random Variable Stream Generator") +{ +} + +double +BinomialTestCase::ChiSquaredTest(Ptr rng) const +{ + uint32_t trials = 10; + double probability = 0.5; + + gsl_histogram* h = gsl_histogram_alloc(trials + 1); + auto range = UniformHistogramBins(h, 0, trials); + + std::vector expected(trials + 1); + for (std::size_t i = 0; i < trials + 1; ++i) + { + expected[i] = N_MEASUREMENTS * gsl_ran_binomial_pdf(i, probability, trials); + } + + double chiSquared = ChiSquared(h, expected, rng); + + gsl_histogram_free(h); + return chiSquared; +} + +void +BinomialTestCase::DoRun() +{ + NS_LOG_FUNCTION(this); + SetTestSuiteSeed(); + + uint32_t trials = 10; + double probability = 0.5; + + auto generator = RngGenerator(); + double sum = ChiSquaredsAverage(&generator, N_RUNS); + double maxStatistic = gsl_cdf_chisq_Qinv(0.05, trials); + NS_TEST_ASSERT_MSG_LT(sum, maxStatistic, "Chi-squared statistic out of range"); + + // Create the RNG with the specified range. + Ptr x = CreateObject(); + x->SetAttribute("Trials", IntegerValue(trials)); + x->SetAttribute("Probability", DoubleValue(probability)); + + // Calculate the mean of these values. + double mean = trials * probability; + double valueMean = Average(x); + double expectedMean = mean; + double expectedRms = std::sqrt(mean / N_MEASUREMENTS); + + // Test that values have approximately the right mean value. + NS_TEST_ASSERT_MSG_EQ_TOL(valueMean, + expectedMean, + expectedRms * TOLERANCE, + "Wrong mean value."); +} + +/** + * \ingroup rng-tests + * Test case for antithetic binomial distribution random variable stream generator + */ +class BinomialAntitheticTestCase : public TestCaseBase +{ + public: + // Constructor + BinomialAntitheticTestCase(); + + // Inherited + double ChiSquaredTest(Ptr rng) const override; + + private: + // Inherited + void DoRun() override; + + /** Tolerance for testing rng values against expectation, in rms. */ + static constexpr double TOLERANCE{5}; +}; + +BinomialAntitheticTestCase::BinomialAntitheticTestCase() + : TestCaseBase("Antithetic Binomial Random Variable Stream Generator") +{ +} + +double +BinomialAntitheticTestCase::ChiSquaredTest(Ptr rng) const +{ + uint32_t trials = 10; + double probability = 0.5; + + gsl_histogram* h = gsl_histogram_alloc(trials + 1); + auto range = UniformHistogramBins(h, 0, trials); + + std::vector expected(trials + 1); + for (std::size_t i = 0; i < trials + 1; ++i) + { + expected[i] = N_MEASUREMENTS * gsl_ran_binomial_pdf(i, probability, trials); + } + + double chiSquared = ChiSquared(h, expected, rng); + + gsl_histogram_free(h); + return chiSquared; +} + +void +BinomialAntitheticTestCase::DoRun() +{ + NS_LOG_FUNCTION(this); + SetTestSuiteSeed(); + + uint32_t trials = 10; + double probability = 0.5; + + auto generator = RngGenerator(true); + double sum = ChiSquaredsAverage(&generator, N_RUNS); + double maxStatistic = gsl_cdf_chisq_Qinv(0.05, trials); + NS_TEST_ASSERT_MSG_LT(sum, maxStatistic, "Chi-squared statistic out of range"); + + // Create the RNG with the specified range. + Ptr x = CreateObject(); + x->SetAttribute("Trials", IntegerValue(trials)); + x->SetAttribute("Probability", DoubleValue(probability)); + + // Make this generate antithetic values. + x->SetAttribute("Antithetic", BooleanValue(true)); + + // Calculate the mean of these values. + double mean = trials * probability; + double valueMean = Average(x); + double expectedMean = mean; + double expectedRms = std::sqrt(mean / N_MEASUREMENTS); + + // Test that values have approximately the right mean value. + NS_TEST_ASSERT_MSG_EQ_TOL(valueMean, + expectedMean, + expectedRms * TOLERANCE, + "Wrong mean value."); +} + /** * \ingroup rng-tests * RandomVariableStream test suite, covering all random number variable @@ -2617,6 +2924,10 @@ RandomVariableSuite::RandomVariableSuite() AddTestCase(new EmpiricalAntitheticTestCase); /// Issue #302: NormalRandomVariable produces stale values AddTestCase(new NormalCachingTestCase); + AddTestCase(new BernoulliTestCase); + AddTestCase(new BernoulliAntitheticTestCase); + AddTestCase(new BinomialTestCase); + AddTestCase(new BinomialAntitheticTestCase); } static RandomVariableSuite randomVariableSuite; //!< Static variable for test initialization diff --git a/src/core/test/tuple-value-test-suite.cc b/src/core/test/tuple-value-test-suite.cc index 3e593e99f..2db327dba 100644 --- a/src/core/test/tuple-value-test-suite.cc +++ b/src/core/test/tuple-value-test-suite.cc @@ -62,8 +62,9 @@ class TupleObject : public Object // NOTE EnumValue::Get() return an int, so the tuple element type must be an int // in place of the enum type - using Tuple1Value = TupleValue; //!< Tuple1 attribute value - using Tuple1 = Tuple1Value::result_type; //!< tuple of values + using Tuple1Value = + TupleValue>; //!< Tuple1 attribute value + using Tuple1 = Tuple1Value::result_type; //!< tuple of values using Tuple1Pack = Tuple1Value::value_type; //!< tuple of attribute values using Tuple2 = std::tuple; //!< Tuple2 typedef @@ -207,7 +208,7 @@ TupleValueTestCase::DoRun() TupleObject::Tuple1{"Norwegian", "Wood", TupleObject::VALUE2})); NS_TEST_ASSERT_MSG_EQ(ret1, true, "Setting valid values to tuple 1 failed"); - TupleValue tupleValue1; + TupleValue> tupleValue1; ret1 = tupleObject->GetAttributeFailSafe("StringStringEnumTuple", tupleValue1); NS_TEST_ASSERT_MSG_EQ(ret1, true, "Getting values for tuple 1 failed"); diff --git a/src/core/test/val-array-test-suite.cc b/src/core/test/val-array-test-suite.cc index 8ac7dd534..4c06e34cd 100644 --- a/src/core/test/val-array-test-suite.cc +++ b/src/core/test/val-array-test-suite.cc @@ -42,21 +42,21 @@ class ValArrayTestCase : public TestCase { public: /** Default constructor*/ - ValArrayTestCase() = default; + ValArrayTestCase() = default; /** * Constructor * * \param [in] name reference name */ - ValArrayTestCase(const std::string& name); + ValArrayTestCase(const std::string& name); /** Destructor. */ - ~ValArrayTestCase() override; + ~ValArrayTestCase() override; /** * \brief Copy constructor. * Instruct the compiler to generate the implicitly declared copy constructor */ - ValArrayTestCase(const ValArrayTestCase&) = default; + ValArrayTestCase(const ValArrayTestCase&) = default; /** * \brief Copy assignment operator. * Instruct the compiler to generate the implicitly declared copy assignment operator. @@ -67,7 +67,7 @@ class ValArrayTestCase : public TestCase * \brief Move constructor. * Instruct the compiler to generate the implicitly declared move constructor */ - ValArrayTestCase(ValArrayTestCase&&) = default; + ValArrayTestCase(ValArrayTestCase&&) = default; /** * \brief Move assignment operator. * Instruct the compiler to generate the implicitly declared copy constructor @@ -86,7 +86,7 @@ ValArrayTestCase::ValArrayTestCase(const std::string& name) } template -ValArrayTestCase::~ValArrayTestCase() +ValArrayTestCase::~ValArrayTestCase() { } diff --git a/src/csma-layout/CMakeLists.txt b/src/csma-layout/CMakeLists.txt index 56574078c..d985f8e9c 100644 --- a/src/csma-layout/CMakeLists.txt +++ b/src/csma-layout/CMakeLists.txt @@ -3,7 +3,6 @@ build_lib( SOURCE_FILES model/csma-star-helper.cc HEADER_FILES model/csma-star-helper.h LIBRARIES_TO_LINK - ${libnetwork} ${libinternet} ${libcsma} ${libpoint-to-point} diff --git a/src/csma/CMakeLists.txt b/src/csma/CMakeLists.txt index 52884036c..2c97becd5 100644 --- a/src/csma/CMakeLists.txt +++ b/src/csma/CMakeLists.txt @@ -11,5 +11,4 @@ build_lib( model/csma-channel.h model/csma-net-device.h LIBRARIES_TO_LINK ${libnetwork} - TEST_SOURCES ${test_sources} ) diff --git a/src/csma/model/csma-channel.cc b/src/csma/model/csma-channel.cc index 2a0defc8c..37ace2f98 100644 --- a/src/csma/model/csma-channel.cc +++ b/src/csma/model/csma-channel.cc @@ -191,7 +191,7 @@ CsmaChannel::TransmitStart(Ptr p, uint32_t srcId) } NS_LOG_LOGIC("switch to TRANSMITTING"); - m_currentPkt = p->Copy(); + m_currentPkt = p; m_currentSrc = srcId; m_state = TRANSMITTING; return true; @@ -200,7 +200,7 @@ CsmaChannel::TransmitStart(Ptr p, uint32_t srcId) bool CsmaChannel::IsActive(uint32_t deviceId) { - return (m_deviceList[deviceId].active); + return m_deviceList[deviceId].active; } bool @@ -234,7 +234,7 @@ CsmaChannel::TransmitEnd() m_delay, &CsmaNetDevice::Receive, it->devicePtr, - m_currentPkt->Copy(), + m_currentPkt, m_deviceList[m_currentSrc].devicePtr); } } diff --git a/src/csma/model/csma-channel.h b/src/csma/model/csma-channel.h index da4e948da..92263545e 100644 --- a/src/csma/model/csma-channel.h +++ b/src/csma/model/csma-channel.h @@ -325,7 +325,7 @@ class CsmaChannel : public Channel * packet to have been transmitted on the channel if the channel is * free.) */ - Ptr m_currentPkt; + Ptr m_currentPkt; /** * Device Id of the source that is currently transmitting on the diff --git a/src/csma/model/csma-net-device.cc b/src/csma/model/csma-net-device.cc index bb0b93894..1ce663ab5 100644 --- a/src/csma/model/csma-net-device.cc +++ b/src/csma/model/csma-net-device.cc @@ -62,7 +62,7 @@ CsmaNetDevice::GetTypeId() .AddAttribute("EncapsulationMode", "The link-layer encapsulation type to use.", EnumValue(DIX), - MakeEnumAccessor(&CsmaNetDevice::SetEncapsulationMode), + MakeEnumAccessor(&CsmaNetDevice::SetEncapsulationMode), MakeEnumChecker(DIX, "Dix", LLC, "Llc")) .AddAttribute("SendEnable", "Enable or disable the transmitter section of the device.", @@ -695,7 +695,7 @@ CsmaNetDevice::SetReceiveErrorModel(Ptr em) } void -CsmaNetDevice::Receive(Ptr packet, Ptr senderDevice) +CsmaNetDevice::Receive(Ptr packet, Ptr senderDevice) { NS_LOG_FUNCTION(packet << senderDevice); NS_LOG_LOGIC("UID is " << packet->GetUid()); @@ -724,7 +724,9 @@ CsmaNetDevice::Receive(Ptr packet, Ptr senderDevice) return; } - if (m_receiveErrorModel && m_receiveErrorModel->IsCorrupt(packet)) + Ptr pktCopy = packet->Copy(); + + if (m_receiveErrorModel && m_receiveErrorModel->IsCorrupt(pktCopy)) { NS_LOG_LOGIC("Dropping pkt due to error model "); m_phyRxDropTrace(packet); @@ -735,16 +737,15 @@ CsmaNetDevice::Receive(Ptr packet, Ptr senderDevice) // Trace sinks will expect complete packets, not packets without some of the // headers. // - Ptr originalPacket = packet->Copy(); EthernetTrailer trailer; - packet->RemoveTrailer(trailer); + pktCopy->RemoveTrailer(trailer); if (Node::ChecksumEnabled()) { trailer.EnableFcs(true); } - bool crcGood = trailer.CheckFcs(packet); + bool crcGood = trailer.CheckFcs(pktCopy); if (!crcGood) { NS_LOG_INFO("CRC error on Packet " << packet); @@ -753,7 +754,7 @@ CsmaNetDevice::Receive(Ptr packet, Ptr senderDevice) } EthernetHeader header(false); - packet->RemoveHeader(header); + pktCopy->RemoveHeader(header); NS_LOG_LOGIC("Pkt source is " << header.GetSource()); NS_LOG_LOGIC("Pkt destination is " << header.GetDestination()); @@ -767,16 +768,16 @@ CsmaNetDevice::Receive(Ptr packet, Ptr senderDevice) // if (header.GetLengthType() <= 1500) { - NS_ASSERT(packet->GetSize() >= header.GetLengthType()); - uint32_t padlen = packet->GetSize() - header.GetLengthType(); + NS_ASSERT(pktCopy->GetSize() >= header.GetLengthType()); + uint32_t padlen = pktCopy->GetSize() - header.GetLengthType(); NS_ASSERT(padlen <= 46); if (padlen > 0) { - packet->RemoveAtEnd(padlen); + pktCopy->RemoveAtEnd(padlen); } LlcSnapHeader llc; - packet->RemoveHeader(llc); + pktCopy->RemoveHeader(llc); protocol = llc.GetType(); } else @@ -811,12 +812,12 @@ CsmaNetDevice::Receive(Ptr packet, Ptr senderDevice) // hook and pass a copy up to the promiscuous callback. Pass a copy to // make sure that nobody messes with our packet. // - m_promiscSnifferTrace(originalPacket); + m_promiscSnifferTrace(packet); if (!m_promiscRxCallback.IsNull()) { - m_macPromiscRxTrace(originalPacket); + m_macPromiscRxTrace(packet); m_promiscRxCallback(this, - packet, + pktCopy, protocol, header.GetSource(), header.GetDestination(), @@ -830,9 +831,9 @@ CsmaNetDevice::Receive(Ptr packet, Ptr senderDevice) // if (packetType != PACKET_OTHERHOST) { - m_snifferTrace(originalPacket); - m_macRxTrace(originalPacket); - m_rxCallback(this, packet, protocol, header.GetSource()); + m_snifferTrace(packet); + m_macRxTrace(packet); + m_rxCallback(this, pktCopy, protocol, header.GetSource()); } } diff --git a/src/csma/model/csma-net-device.h b/src/csma/model/csma-net-device.h index ff72aad2a..af092bfa6 100644 --- a/src/csma/model/csma-net-device.h +++ b/src/csma/model/csma-net-device.h @@ -172,7 +172,7 @@ class CsmaNetDevice : public NetDevice * \param p a reference to the received packet * \param sender the CsmaNetDevice that transmitted the packet in the first place */ - void Receive(Ptr p, Ptr sender); + void Receive(Ptr p, Ptr sender); /** * Is the send side of the network device enabled? diff --git a/src/dsdv/CMakeLists.txt b/src/dsdv/CMakeLists.txt index 11c2d95ae..6b5877b64 100644 --- a/src/dsdv/CMakeLists.txt +++ b/src/dsdv/CMakeLists.txt @@ -12,6 +12,7 @@ build_lib( model/dsdv-packet.h model/dsdv-routing-protocol.h model/dsdv-rtable.h - LIBRARIES_TO_LINK ${libinternet} + LIBRARIES_TO_LINK ${libmesh} + ${libinternet-apps} TEST_SOURCES test/dsdv-testcase.cc ) diff --git a/src/dsdv/model/dsdv-routing-protocol.cc b/src/dsdv/model/dsdv-routing-protocol.cc index c5681653b..0a693588e 100644 --- a/src/dsdv/model/dsdv-routing-protocol.cc +++ b/src/dsdv/model/dsdv-routing-protocol.cc @@ -932,7 +932,7 @@ RoutingProtocol::SendPeriodicUpdate() else { dsdvHeader.SetDst(i->second.GetDestination()); - dsdvHeader.SetDstSeqno((i->second.GetSeqNo())); + dsdvHeader.SetDstSeqno(i->second.GetSeqNo()); dsdvHeader.SetHopCount(i->second.GetHop() + 1); packet->AddHeader(dsdvHeader); } diff --git a/src/dsdv/model/dsdv-rtable.h b/src/dsdv/model/dsdv-rtable.h index 6ee6c63a1..e62bd06f1 100644 --- a/src/dsdv/model/dsdv-rtable.h +++ b/src/dsdv/model/dsdv-rtable.h @@ -233,7 +233,7 @@ class RoutingTableEntry */ Time GetSettlingTime() const { - return (m_settlingTime); + return m_settlingTime; } /** diff --git a/src/dsdv/test/dsdv-testcase.cc b/src/dsdv/test/dsdv-testcase.cc index 0248c4ec8..508bb82b7 100644 --- a/src/dsdv/test/dsdv-testcase.cc +++ b/src/dsdv/test/dsdv-testcase.cc @@ -41,7 +41,6 @@ #include "ns3/string.h" #include "ns3/test.h" #include "ns3/uinteger.h" -#include "ns3/v4ping-helper.h" using namespace ns3; diff --git a/src/dsr/CMakeLists.txt b/src/dsr/CMakeLists.txt index 1b91253e5..6ec437d85 100644 --- a/src/dsr/CMakeLists.txt +++ b/src/dsr/CMakeLists.txt @@ -30,7 +30,6 @@ build_lib( model/dsr-routing.h model/dsr-rreq-table.h model/dsr-rsendbuff.h - LIBRARIES_TO_LINK ${libinternet} - ${libwifi} + LIBRARIES_TO_LINK ${libmesh} TEST_SOURCES test/dsr-test-suite.cc ) diff --git a/src/dsr/examples/dsr.cc b/src/dsr/examples/dsr.cc index 39b6373c0..7b20127dc 100644 --- a/src/dsr/examples/dsr.cc +++ b/src/dsr/examples/dsr.cc @@ -29,7 +29,6 @@ */ #include "ns3/applications-module.h" -#include "ns3/config-store-module.h" #include "ns3/core-module.h" #include "ns3/dsr-module.h" #include "ns3/internet-module.h" diff --git a/src/dsr/model/dsr-options.cc b/src/dsr/model/dsr-options.cc index 8dd292c80..c1f2edea6 100644 --- a/src/dsr/model/dsr-options.cc +++ b/src/dsr/model/dsr-options.cc @@ -755,7 +755,7 @@ DsrOptionRreq::Process(Ptr packet, // { // dsr->UseExtends (m_finalRoute); // } - sourceRoute.SetSegmentsLeft((m_finalRoute.size() - 2)); + sourceRoute.SetSegmentsLeft(m_finalRoute.size() - 2); // The salvage value here is 0 sourceRoute.SetSalvage(0); Ipv4Address nextHop = @@ -860,7 +860,7 @@ DsrOptionRreq::Process(Ptr packet, // { // dsr->UseExtends (saveRoute); // } - sourceRoute.SetSegmentsLeft((saveRoute.size() - 2)); + sourceRoute.SetSegmentsLeft(saveRoute.size() - 2); uint8_t salvage = 0; sourceRoute.SetSalvage(salvage); Ipv4Address nextHop = @@ -1123,7 +1123,7 @@ DsrOptionRrep::Process(Ptr packet, DsrOptionSRHeader sourceRoute; NS_LOG_DEBUG("The route length " << nodeList.size()); sourceRoute.SetNodesAddress(nodeList); - sourceRoute.SetSegmentsLeft((nodeList.size() - 2)); + sourceRoute.SetSegmentsLeft(nodeList.size() - 2); sourceRoute.SetSalvage(0); Ipv4Address nextHop = SearchNextHop(ipv4Address, nodeList); // Get the next hop address NS_LOG_DEBUG("The nextHop address " << nextHop); @@ -1759,7 +1759,7 @@ DsrOptionAckReq::Process(Ptr packet, DsrOptionAckReqHeader ackReq; p->RemoveHeader(ackReq); /* - * Get the node with ip address and get the dsr extension and reoute cache objects + * Get the node with ip address and get the dsr extension and route cache objects */ Ptr node = GetNodeWithAddress(ipv4Address); Ptr dsr = node->GetObject(); diff --git a/src/dsr/model/dsr-rcache.h b/src/dsr/model/dsr-rcache.h index 0d6ea3be2..9401e1f82 100644 --- a/src/dsr/model/dsr-rcache.h +++ b/src/dsr/model/dsr-rcache.h @@ -345,41 +345,15 @@ class DsrRouteCacheEntry void Print(std::ostream& os) const; /** - * \brief Compare the route cache entry + * \brief Compare the route cache entry. Only the paths are compared. * \param o entry to compare - * \return true if equal + * \return true if both route cache entries are equal */ bool operator==(const DsrRouteCacheEntry& o) const { - if (m_path.size() != o.m_path.size()) - { - NS_ASSERT(false); - return false; - } - auto j = o.m_path.begin(); - for (auto i = m_path.begin(); i != m_path.end(); i++, j++) - { - /* - * Verify if neither the entry are not 0 and they equal to each other - */ - if (((*i) == nullptr) || ((*j) == nullptr)) - { - return false; - } - else if (!((*i) == (*j))) - { - return false; - } - else - { - return true; - } - } - return false; + return m_path == o.m_path; } - // \} - private: Timer m_ackTimer; ///< RREP_ACK timer Ipv4Address m_dst; ///< The destination Ip address diff --git a/src/dsr/model/dsr-routing.cc b/src/dsr/model/dsr-routing.cc index ddfd8602e..38c0d6d08 100644 --- a/src/dsr/model/dsr-routing.cc +++ b/src/dsr/model/dsr-routing.cc @@ -927,7 +927,7 @@ DsrRouting::CheckSendBuffer() { m_routeCache->UseExtends(errorRoute); } - sourceRoute.SetSegmentsLeft((errorRoute.size() - 2)); + sourceRoute.SetSegmentsLeft(errorRoute.size() - 2); uint8_t salvage = 0; sourceRoute.SetSalvage(salvage); Ipv4Address nextHop = @@ -1000,12 +1000,12 @@ DsrRouting::CheckSendBuffer() return; } uint8_t salvage = 0; - sourceRoute.SetNodesAddress( - nodeList); // Save the whole route in the source route header of the packet - sourceRoute.SetSegmentsLeft( - (nodeList.size() - 2)); // The segmentsLeft field will indicate the hops to go + // Save the whole route in the source route header of the packet + sourceRoute.SetNodesAddress(nodeList); + // The segmentsLeft field will indicate the hops to go + sourceRoute.SetSegmentsLeft(nodeList.size() - 2); sourceRoute.SetSalvage(salvage); - /// When found a route and use it, UseExtends to the link cache + // When found a route and use it, UseExtends to the link cache if (m_routeCache->IsLinkCache()) { m_routeCache->UseExtends(nodeList); @@ -1273,8 +1273,8 @@ DsrRouting::PacketNewRoute(Ptr packet, { m_routeCache->UseExtends(nodeList); } - sourceRoute.SetSegmentsLeft( - (nodeList.size() - 2)); // The segmentsLeft field will indicate the hops to go + // The segmentsLeft field will indicate the hops to go + sourceRoute.SetSegmentsLeft(nodeList.size() - 2); sourceRoute.SetSalvage(salvage); uint8_t length = sourceRoute.GetLength(); @@ -1431,7 +1431,7 @@ DsrRouting::SendUnreachError(Ipv4Address unreachNode, { m_routeCache->UseExtends(nodeList); } - sourceRoute.SetSegmentsLeft((nodeList.size() - 2)); + sourceRoute.SetSegmentsLeft(nodeList.size() - 2); uint8_t srLength = sourceRoute.GetLength(); uint8_t length = (srLength + rerrLength); @@ -1600,8 +1600,8 @@ DsrRouting::Send(Ptr packet, { m_routeCache->UseExtends(nodeList); } - sourceRoute.SetSegmentsLeft( - (nodeList.size() - 2)); // The segmentsLeft field will indicate the hops to go + // The segmentsLeft field will indicate the hops to go + sourceRoute.SetSegmentsLeft(nodeList.size() - 2); sourceRoute.SetSalvage(salvage); uint8_t length = sourceRoute.GetLength(); @@ -2491,10 +2491,10 @@ DsrRouting::SalvagePacket(Ptr packet, salvage++; DsrOptionSRHeader sourceRoute; sourceRoute.SetSalvage(salvage); - sourceRoute.SetNodesAddress( - nodeList); // Save the whole route in the source route header of the packet - sourceRoute.SetSegmentsLeft( - (nodeList.size() - 2)); // The segmentsLeft field will indicate the hops to go + // Save the whole route in the source route header of the packet + sourceRoute.SetNodesAddress(nodeList); + // The segmentsLeft field will indicate the hops to go + sourceRoute.SetSegmentsLeft(nodeList.size() - 2); /// When found a route and use it, UseExtends to the link cache if (m_routeCache->IsLinkCache()) { @@ -3000,7 +3000,7 @@ DsrRouting::SendErrorRequest(DsrOptionRerrUnreachHeader& rerr, uint8_t protocol) { m_routeCache->UseExtends(ip); } - sourceRoute.SetSegmentsLeft((ip.size() - 2)); + sourceRoute.SetSegmentsLeft(ip.size() - 2); sourceRoute.SetSalvage(salvage); Ipv4Address nextHop = SearchNextHop(m_mainAddress, ip); // Get the next hop address NS_LOG_DEBUG("The nextHop address " << nextHop); @@ -3237,7 +3237,7 @@ DsrRouting::RouteRequestTimerExpire(Ptr packet, { m_routeCache->UseExtends(ip); } - sourceRoute.SetSegmentsLeft((ip.size() - 2)); + sourceRoute.SetSegmentsLeft(ip.size() - 2); /// Set the salvage value to 0 sourceRoute.SetSalvage(0); Ipv4Address nextHop = SearchNextHop(m_mainAddress, ip); // Get the next hop address diff --git a/src/energy/examples/CMakeLists.txt b/src/energy/examples/CMakeLists.txt index 1644c8668..da1bc0963 100644 --- a/src/energy/examples/CMakeLists.txt +++ b/src/energy/examples/CMakeLists.txt @@ -5,7 +5,7 @@ build_lib_example( ${libenergy} ) -build_example( +build_lib_example( NAME generic-battery-wifiradio-example SOURCE_FILES generic-battery-wifiradio-example.cc LIBRARIES_TO_LINK diff --git a/src/energy/examples/basic-energy-model-test.cc b/src/energy/examples/basic-energy-model-test.cc index 7221dfec5..163a2225b 100644 --- a/src/energy/examples/basic-energy-model-test.cc +++ b/src/energy/examples/basic-energy-model-test.cc @@ -145,7 +145,7 @@ BasicEnergyUpdateTest::StateSwitchTest(WifiPhyState state) // retrieve device energy model from energy source DeviceEnergyModelContainer models = source->FindDeviceEnergyModels("ns3::WifiRadioEnergyModel"); // check list - if ((models.GetN() == 0)) + if (models.GetN() == 0) { std::cerr << "Model list is empty!." << std::endl; return true; diff --git a/src/energy/examples/generic-battery-discharge-example.py b/src/energy/examples/generic-battery-discharge-example.py index a6dfde1c9..379c564d9 100644 --- a/src/energy/examples/generic-battery-discharge-example.py +++ b/src/energy/examples/generic-battery-discharge-example.py @@ -20,7 +20,15 @@ # Demonstrates the discharge behavior of a NIMH battery discharged with a # constant current of 6.5 A (1C) -from ns import ns +try: + from ns import ns +except ModuleNotFoundError: + raise SystemExit( + "Error: ns3 Python module not found;" + " Python bindings may not be enabled" + " or your PYTHONPATH might not be properly configured" + ) + def main(argv): """The main function in this Battery discharge example @@ -32,7 +40,7 @@ def main(argv): ns.core.LogComponentEnable("GenericBatteryModel", ns.core.LOG_LEVEL_DEBUG) node = ns.network.Node() - batteryHelper = ns.energy.GenericBatteryModelHelper() + batteryHelper = ns.energy.GenericBatteryModelHelper() batteryModel = ns.CreateObject("GenericBatteryModel") devicesEnergyModel = ns.energy.SimpleDeviceEnergyModel() @@ -40,14 +48,14 @@ def main(argv): batteryModel.SetAttribute("MaxCapacity", ns.core.DoubleValue(7.0)) # Q batteryModel.SetAttribute("NominalVoltage", ns.core.DoubleValue(1.18)) # Vnom - batteryModel.SetAttribute("NominalCapacity", ns.core.DoubleValue(6.25)) # QNom + batteryModel.SetAttribute("NominalCapacity", ns.core.DoubleValue(6.25)) # QNom - batteryModel.SetAttribute("ExponentialVoltage", ns.core.DoubleValue(1.28)) # Vexp - batteryModel.SetAttribute("ExponentialCapacity", ns.core.DoubleValue(1.3)) # Qexp + batteryModel.SetAttribute("ExponentialVoltage", ns.core.DoubleValue(1.28)) # Vexp + batteryModel.SetAttribute("ExponentialCapacity", ns.core.DoubleValue(1.3)) # Qexp - batteryModel.SetAttribute("InternalResistance", ns.core.DoubleValue(0.0046)) # R - batteryModel.SetAttribute("TypicalDischargeCurrent", ns.core.DoubleValue(1.3)) # i typical - batteryModel.SetAttribute("CutoffVoltage", ns.core.DoubleValue(1.0)) # End of charge. + batteryModel.SetAttribute("InternalResistance", ns.core.DoubleValue(0.0046)) # R + batteryModel.SetAttribute("TypicalDischargeCurrent", ns.core.DoubleValue(1.3)) # i typical + batteryModel.SetAttribute("CutoffVoltage", ns.core.DoubleValue(1.0)) # End of charge. batteryModel.SetAttribute("BatteryType", ns.core.EnumValue(ns.NIMH_NICD)) # Battery type @@ -57,14 +65,12 @@ def main(argv): devicesEnergyModel.SetCurrentA(6.5) - ns.core.Simulator.Stop(ns.core.Seconds(3600)) ns.core.Simulator.Run() ns.core.Simulator.Destroy() - -if __name__ == '__main__': +if __name__ == "__main__": import sys - main(sys.argv) + main(sys.argv) diff --git a/src/energy/model/generic-battery-model.cc b/src/energy/model/generic-battery-model.cc index 35e1b5b74..cbf523608 100644 --- a/src/energy/model/generic-battery-model.cc +++ b/src/energy/model/generic-battery-model.cc @@ -104,7 +104,7 @@ GenericBatteryModel::GetTypeId() .AddAttribute("BatteryType", "Indicates the battery type used by the model", EnumValue(LION_LIPO), - MakeEnumAccessor(&GenericBatteryModel::m_batteryType), + MakeEnumAccessor(&GenericBatteryModel::m_batteryType), MakeEnumChecker(LION_LIPO, "LION_LIPO", NIMH_NICD, diff --git a/src/energy/model/li-ion-energy-source.h b/src/energy/model/li-ion-energy-source.h index 224e3de82..4dd01bcc2 100644 --- a/src/energy/model/li-ion-energy-source.h +++ b/src/energy/model/li-ion-energy-source.h @@ -22,6 +22,7 @@ #include "energy-source.h" +#include "ns3/deprecated.h" #include "ns3/event-id.h" #include "ns3/nstime.h" #include "ns3/traced-value.h" diff --git a/src/fd-net-device/CMakeLists.txt b/src/fd-net-device/CMakeLists.txt index d7d2c3062..84c6deda8 100644 --- a/src/fd-net-device/CMakeLists.txt +++ b/src/fd-net-device/CMakeLists.txt @@ -26,6 +26,9 @@ check_include_file( ) include(FindPkgConfig) +set(DPDK_INCLUDE_DIRS + "" +) if(PKG_CONFIG_FOUND) pkg_check_modules( DPDK @@ -137,6 +140,8 @@ if(${ENABLE_FDNETDEV}) FdNetDevice ) + set(emu_sources) + set(emu_headers) if(${ENABLE_EMUNETDEV}) set(emu_sources helper/emu-fd-net-device-helper.cc @@ -172,6 +177,8 @@ if(${ENABLE_FDNETDEV}) ) endif() + set(tap_sources) + set(tap_headers) if(${ENABLE_TAPNETDEV}) set(tap_sources helper/tap-fd-net-device-helper.cc @@ -190,6 +197,7 @@ if(${ENABLE_FDNETDEV}) helper/creator-utils.cc helper/encode-decode.cc helper/tap-device-creator.cc + LIBRARIES_TO_LINK ${libnetwork} EXECUTABLE_DIRECTORY_PATH ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/src/fd-net-device/ INSTALL_DIRECTORY_PATH ${CMAKE_INSTALL_LIBEXECDIR}/ns3 @@ -208,6 +216,8 @@ if(${ENABLE_FDNETDEV}) ) endif() + set(netmap_sources) + set(netmap_headers) if(${ENABLE_NETMAP_EMU}) set(netmap_sources helper/netmap-net-device-helper.cc @@ -241,6 +251,9 @@ if(${ENABLE_FDNETDEV}) ) endif() + set(dpdk_sources) + set(dpdk_headers) + set(dpdk_libraries) if(${ENABLE_DPDKDEVNET}) set(dpdk_sources model/dpdk-net-device.cc diff --git a/src/fd-net-device/examples/realtime-fd2fd-onoff.cc b/src/fd-net-device/examples/realtime-fd2fd-onoff.cc index 19f3fa64e..2d35cffaa 100644 --- a/src/fd-net-device/examples/realtime-fd2fd-onoff.cc +++ b/src/fd-net-device/examples/realtime-fd2fd-onoff.cc @@ -28,10 +28,10 @@ // | fd-net-device |--------------| fd-net-device | // +----------------+ +----------------+ // -// This example is aimed at measuring the thoughput of the FdNetDevice +// This example is aimed at measuring the throughput of the FdNetDevice // in a pure simulation. For this purpose two FdNetDevices, attached to // different nodes but in a same simulation, are connected using a socket pair. -// TCP traffic is sent at a saturating data rate. Then the thoughput can +// TCP traffic is sent at a saturating data rate. Then the throughput can // be obtained from the generated .pcap files. // // Steps to run the experiment: diff --git a/src/fd-net-device/helper/tap-device-creator.cc b/src/fd-net-device/helper/tap-device-creator.cc index fc4ff40f4..ccfa97311 100644 --- a/src/fd-net-device/helper/tap-device-creator.cc +++ b/src/fd-net-device/helper/tap-device-creator.cc @@ -17,6 +17,8 @@ #include "creator-utils.h" +#include "ns3/mac48-address.h" + #include #include #include @@ -38,18 +40,6 @@ #define TAP_MAGIC 95549 -// -// Lots of the following helper code taken from corresponding functions in src/node. -// -#define ASCII_DOT (0x2e) -#define ASCII_ZERO (0x30) -#define ASCII_a (0x41) -#define ASCII_z (0x5a) -#define ASCII_A (0x61) -#define ASCII_Z (0x7a) -#define ASCII_COLON (0x3a) -#define ASCII_ZERO (0x30) - using namespace ns3; /** @@ -62,54 +52,6 @@ struct in6_ifreq int32_t ifr6_ifindex; //!< interface index }; -char -AsciiToLowCase(char c) -{ - if (c >= ASCII_a && c <= ASCII_z) - { - return c; - } - else if (c >= ASCII_A && c <= ASCII_Z) - { - return c + (ASCII_a - ASCII_A); - } - else - { - return c; - } -} - -void -AsciiToMac48(const char* str, uint8_t addr[6]) -{ - int i = 0; - while (*str != 0 && i < 6) - { - uint8_t byte = 0; - while (*str != ASCII_COLON && *str != 0) - { - byte <<= 4; - char low = AsciiToLowCase(*str); - if (low >= ASCII_a) - { - byte |= low - ASCII_a + 10; - } - else - { - byte |= low - ASCII_ZERO; - } - str++; - } - addr[i] = byte; - i++; - if (*str == 0) - { - break; - } - str++; - } -} - void SetIpv4(const char* deviceName, const char* ip, const char* netmask) { @@ -189,7 +131,7 @@ SetMacAddress(int fd, const char* mac) memset(&ifr, 0, sizeof(struct ifreq)); ifr.ifr_hwaddr.sa_family = 1; // this is ARPHRD_ETHER from if_arp.h - AsciiToMac48(mac, (uint8_t*)ifr.ifr_hwaddr.sa_data); + Mac48Address(mac).CopyTo((uint8_t*)ifr.ifr_hwaddr.sa_data); ABORT_IF(ioctl(fd, SIOCSIFHWADDR, &ifr) == -1, "Could not set MAC address", true); LOG("Set device MAC address to " << mac); } diff --git a/src/fd-net-device/model/fd-net-device.cc b/src/fd-net-device/model/fd-net-device.cc index 70185637a..b7ef2620e 100644 --- a/src/fd-net-device/model/fd-net-device.cc +++ b/src/fd-net-device/model/fd-net-device.cc @@ -106,7 +106,7 @@ FdNetDevice::GetTypeId() .AddAttribute("EncapsulationMode", "The link-layer encapsulation type to use.", EnumValue(DIX), - MakeEnumAccessor(&FdNetDevice::m_encapMode), + MakeEnumAccessor(&FdNetDevice::m_encapMode), MakeEnumChecker(DIX, "Dix", LLC, "Llc", DIXPI, "DixPi")) .AddAttribute("RxQueueSize", "Maximum size of the read queue. " diff --git a/src/flow-monitor/CMakeLists.txt b/src/flow-monitor/CMakeLists.txt index fe4788a3b..1628cbb34 100644 --- a/src/flow-monitor/CMakeLists.txt +++ b/src/flow-monitor/CMakeLists.txt @@ -19,5 +19,4 @@ build_lib( model/ipv6-flow-classifier.h model/ipv6-flow-probe.h LIBRARIES_TO_LINK ${libinternet} - ${libstats} ) diff --git a/src/flow-monitor/examples/flowmon-parse-results.py b/src/flow-monitor/examples/flowmon-parse-results.py index 00e4fb854..afe68aa09 100644 --- a/src/flow-monitor/examples/flowmon-parse-results.py +++ b/src/flow-monitor/examples/flowmon-parse-results.py @@ -1,18 +1,20 @@ from __future__ import division -import sys + import os +import sys + try: from xml.etree import cElementTree as ElementTree except ImportError: from xml.etree import ElementTree + def parse_time_ns(tm): - if tm.endswith('ns'): + if tm.endswith("ns"): return float(tm[:-2]) raise ValueError(tm) - ## FiveTuple class FiveTuple(object): ## class variables @@ -28,17 +30,19 @@ class FiveTuple(object): # destination port ## @var __slots_ # class variable list - __slots_ = ['sourceAddress', 'destinationAddress', 'protocol', 'sourcePort', 'destinationPort'] + __slots_ = ["sourceAddress", "destinationAddress", "protocol", "sourcePort", "destinationPort"] + def __init__(self, el): - '''! The initializer. + """! The initializer. @param self The object pointer. @param el The element. - ''' - self.sourceAddress = el.get('sourceAddress') - self.destinationAddress = el.get('destinationAddress') - self.sourcePort = int(el.get('sourcePort')) - self.destinationPort = int(el.get('destinationPort')) - self.protocol = int(el.get('protocol')) + """ + self.sourceAddress = el.get("sourceAddress") + self.destinationAddress = el.get("destinationAddress") + self.sourcePort = int(el.get("sourcePort")) + self.destinationPort = int(el.get("destinationPort")) + self.protocol = int(el.get("protocol")) + ## Histogram class Histogram(object): @@ -47,17 +51,21 @@ class Histogram(object): # histogram bins ## @var __slots_ # class variable list - __slots_ = 'bins', 'nbins', 'number_of_flows' + __slots_ = "bins", "nbins", "number_of_flows" + def __init__(self, el=None): - '''! The initializer. + """! The initializer. @param self The object pointer. @param el The element. - ''' + """ self.bins = [] if el is not None: - #self.nbins = int(el.get('nBins')) - for bin in el.findall('bin'): - self.bins.append( (float(bin.get("start")), float(bin.get("width")), int(bin.get("count"))) ) + # self.nbins = int(el.get('nBins')) + for bin in el.findall("bin"): + self.bins.append( + (float(bin.get("start")), float(bin.get("width")), int(bin.get("count"))) + ) + ## Flow class Flow(object): @@ -84,46 +92,63 @@ class Flow(object): # receive duration ## @var __slots_ # class variable list - __slots_ = ['flowId', 'delayMean', 'packetLossRatio', 'rxBitrate', 'txBitrate', - 'fiveTuple', 'packetSizeMean', 'probe_stats_unsorted', - 'hopCount', 'flowInterruptionsHistogram', 'rx_duration'] + __slots_ = [ + "flowId", + "delayMean", + "packetLossRatio", + "rxBitrate", + "txBitrate", + "fiveTuple", + "packetSizeMean", + "probe_stats_unsorted", + "hopCount", + "flowInterruptionsHistogram", + "rx_duration", + ] + def __init__(self, flow_el): - '''! The initializer. + """! The initializer. @param self The object pointer. @param flow_el The element. - ''' - self.flowId = int(flow_el.get('flowId')) - rxPackets = float(flow_el.get('rxPackets')) - txPackets = float(flow_el.get('txPackets')) + """ + self.flowId = int(flow_el.get("flowId")) + rxPackets = float(flow_el.get("rxPackets")) + txPackets = float(flow_el.get("txPackets")) - tx_duration = (parse_time_ns (flow_el.get('timeLastTxPacket')) - parse_time_ns(flow_el.get('timeFirstTxPacket')))*1e-9 - rx_duration = (parse_time_ns (flow_el.get('timeLastRxPacket')) - parse_time_ns(flow_el.get('timeFirstRxPacket')))*1e-9 + tx_duration = ( + parse_time_ns(flow_el.get("timeLastTxPacket")) + - parse_time_ns(flow_el.get("timeFirstTxPacket")) + ) * 1e-9 + rx_duration = ( + parse_time_ns(flow_el.get("timeLastRxPacket")) + - parse_time_ns(flow_el.get("timeFirstRxPacket")) + ) * 1e-9 self.rx_duration = rx_duration self.probe_stats_unsorted = [] if rxPackets: - self.hopCount = float(flow_el.get('timesForwarded')) / rxPackets + 1 + self.hopCount = float(flow_el.get("timesForwarded")) / rxPackets + 1 else: self.hopCount = -1000 if rxPackets: - self.delayMean = float(flow_el.get('delaySum')[:-2]) / rxPackets * 1e-9 - self.packetSizeMean = float(flow_el.get('rxBytes')) / rxPackets + self.delayMean = float(flow_el.get("delaySum")[:-2]) / rxPackets * 1e-9 + self.packetSizeMean = float(flow_el.get("rxBytes")) / rxPackets else: self.delayMean = None self.packetSizeMean = None if rx_duration > 0: - self.rxBitrate = float(flow_el.get('rxBytes'))*8 / rx_duration + self.rxBitrate = float(flow_el.get("rxBytes")) * 8 / rx_duration else: self.rxBitrate = None if tx_duration > 0: - self.txBitrate = float(flow_el.get('txBytes'))*8 / tx_duration + self.txBitrate = float(flow_el.get("txBytes")) * 8 / tx_duration else: self.txBitrate = None - lost = float(flow_el.get('lostPackets')) - #print "rxBytes: %s; txPackets: %s; rxPackets: %s; lostPackets: %s" % (flow_el.get('rxBytes'), txPackets, rxPackets, lost) + lost = float(flow_el.get("lostPackets")) + # print "rxBytes: %s; txPackets: %s; rxPackets: %s; lostPackets: %s" % (flow_el.get('rxBytes'), txPackets, rxPackets, lost) if rxPackets == 0: self.packetLossRatio = None else: - self.packetLossRatio = (lost / (rxPackets + lost)) + self.packetLossRatio = lost / (rxPackets + lost) interrupt_hist_elem = flow_el.find("flowInterruptionsHistogram") if interrupt_hist_elem is None: @@ -131,6 +156,7 @@ class Flow(object): else: self.flowInterruptionsHistogram = Histogram(interrupt_hist_elem) + ## ProbeFlowStats class ProbeFlowStats(object): ## class variables @@ -140,7 +166,8 @@ class ProbeFlowStats(object): # bytes ## @var __slots_ # class variable list - __slots_ = ['probeId', 'packets', 'bytes', 'delayFromFirstProbe'] + __slots_ = ["probeId", "packets", "bytes", "delayFromFirstProbe"] + ## Simulation class Simulation(object): @@ -148,31 +175,33 @@ class Simulation(object): ## @var flows # list of flows def __init__(self, simulation_el): - '''! The initializer. + """! The initializer. @param self The object pointer. @param simulation_el The element. - ''' + """ self.flows = [] - FlowClassifier_el, = simulation_el.findall("Ipv4FlowClassifier") + (FlowClassifier_el,) = simulation_el.findall("Ipv4FlowClassifier") flow_map = {} for flow_el in simulation_el.findall("FlowStats/Flow"): flow = Flow(flow_el) flow_map[flow.flowId] = flow self.flows.append(flow) for flow_cls in FlowClassifier_el.findall("Flow"): - flowId = int(flow_cls.get('flowId')) + flowId = int(flow_cls.get("flowId")) flow_map[flowId].fiveTuple = FiveTuple(flow_cls) for probe_elem in simulation_el.findall("FlowProbes/FlowProbe"): - probeId = int(probe_elem.get('index')) + probeId = int(probe_elem.get("index")) for stats in probe_elem.findall("FlowStats"): - flowId = int(stats.get('flowId')) + flowId = int(stats.get("flowId")) s = ProbeFlowStats() - s.packets = int(stats.get('packets')) - s.bytes = float(stats.get('bytes')) + s.packets = int(stats.get("packets")) + s.bytes = float(stats.get("bytes")) s.probeId = probeId if s.packets > 0: - s.delayFromFirstProbe = parse_time_ns(stats.get('delayFromFirstProbeSum')) / float(s.packets) + s.delayFromFirstProbe = parse_time_ns( + stats.get("delayFromFirstProbeSum") + ) / float(s.packets) else: s.delayFromFirstProbe = 0 flow_map[flowId].probe_stats_unsorted.append(s) @@ -190,38 +219,46 @@ def main(argv): level += 1 if event == "end": level -= 1 - if level == 0 and elem.tag == 'FlowMonitor': + if level == 0 and elem.tag == "FlowMonitor": sim = Simulation(elem) sim_list.append(sim) - elem.clear() # won't need this any more + elem.clear() # won't need this any more sys.stdout.write(".") sys.stdout.flush() print(" done.") - for sim in sim_list: for flow in sim.flows: t = flow.fiveTuple - proto = {6: 'TCP', 17: 'UDP'} [t.protocol] - print("FlowID: %i (%s %s/%s --> %s/%i)" % \ - (flow.flowId, proto, t.sourceAddress, t.sourcePort, t.destinationAddress, t.destinationPort)) + proto = {6: "TCP", 17: "UDP"}[t.protocol] + print( + "FlowID: %i (%s %s/%s --> %s/%i)" + % ( + flow.flowId, + proto, + t.sourceAddress, + t.sourcePort, + t.destinationAddress, + t.destinationPort, + ) + ) if flow.txBitrate is None: print("\tTX bitrate: None") else: - print("\tTX bitrate: %.2f kbit/s" % (flow.txBitrate*1e-3,)) + print("\tTX bitrate: %.2f kbit/s" % (flow.txBitrate * 1e-3,)) if flow.rxBitrate is None: print("\tRX bitrate: None") else: - print("\tRX bitrate: %.2f kbit/s" % (flow.rxBitrate*1e-3,)) + print("\tRX bitrate: %.2f kbit/s" % (flow.rxBitrate * 1e-3,)) if flow.delayMean is None: print("\tMean Delay: None") else: - print("\tMean Delay: %.2f ms" % (flow.delayMean*1e3,)) + print("\tMean Delay: %.2f ms" % (flow.delayMean * 1e3,)) if flow.packetLossRatio is None: print("\tPacket Loss Ratio: None") else: - print("\tPacket Loss Ratio: %.2f %%" % (flow.packetLossRatio*100)) + print("\tPacket Loss Ratio: %.2f %%" % (flow.packetLossRatio * 100)) -if __name__ == '__main__': +if __name__ == "__main__": main(sys.argv) diff --git a/src/flow-monitor/examples/wifi-olsr-flowmon.py b/src/flow-monitor/examples/wifi-olsr-flowmon.py index 57a3160cd..3c45f8a5f 100644 --- a/src/flow-monitor/examples/wifi-olsr-flowmon.py +++ b/src/flow-monitor/examples/wifi-olsr-flowmon.py @@ -17,17 +17,25 @@ # Authors: Gustavo Carneiro from __future__ import print_function + import sys -from ns import ns +try: + from ns import ns +except ModuleNotFoundError: + raise SystemExit( + "Error: ns3 Python module not found;" + " Python bindings may not be enabled" + " or your PYTHONPATH might not be properly configured" + ) -DISTANCE = 20 # (m) +DISTANCE = 20 # (m) NUM_NODES_SIDE = 3 def main(argv): + from ctypes import c_bool, c_char_p, c_int, create_string_buffer - from ctypes import c_int, c_bool, c_char_p, create_string_buffer NumNodesSide = c_int(2) Plot = c_bool(False) BUFFLEN = 4096 @@ -35,7 +43,11 @@ def main(argv): Results = c_char_p(ResultsBuffer.raw) cmd = ns.CommandLine(__file__) - cmd.AddValue("NumNodesSide", "Grid side number of nodes (total number of nodes will be this number squared)", NumNodesSide) + cmd.AddValue( + "NumNodesSide", + "Grid side number of nodes (total number of nodes will be this number squared)", + NumNodesSide, + ) cmd.AddValue("Results", "Write XML results to file", Results, BUFFLEN) cmd.AddValue("Plot", "Plot the results using the matplotlib python module", Plot) cmd.Parse(argv) @@ -46,8 +58,7 @@ def main(argv): wifiChannel = ns.wifi.YansWifiChannelHelper.Default() wifiPhy.SetChannel(wifiChannel.Create()) ssid = ns.wifi.Ssid("wifi-default") - wifiMac.SetType ("ns3::AdhocWifiMac", - "Ssid", ns.wifi.SsidValue(ssid)) + wifiMac.SetType("ns3::AdhocWifiMac", "Ssid", ns.wifi.SsidValue(ssid)) internet = ns.internet.InternetStackHelper() list_routing = ns.internet.Ipv4ListRoutingHelper() @@ -60,12 +71,16 @@ def main(argv): ipv4Addresses = ns.internet.Ipv4AddressHelper() ipv4Addresses.SetBase(ns.network.Ipv4Address("10.0.0.0"), ns.network.Ipv4Mask("255.255.255.0")) - port = 9 # Discard port(RFC 863) + port = 9 # Discard port(RFC 863) inetAddress = ns.network.InetSocketAddress(ns.network.Ipv4Address("10.0.0.1"), port) onOffHelper = ns.applications.OnOffHelper("ns3::UdpSocketFactory", inetAddress.ConvertTo()) onOffHelper.SetAttribute("DataRate", ns.network.DataRateValue(ns.network.DataRate("100kbps"))) - onOffHelper.SetAttribute("OnTime", ns.core.StringValue ("ns3::ConstantRandomVariable[Constant=1]")) - onOffHelper.SetAttribute("OffTime", ns.core.StringValue ("ns3::ConstantRandomVariable[Constant=0]")) + onOffHelper.SetAttribute( + "OnTime", ns.core.StringValue("ns3::ConstantRandomVariable[Constant=1]") + ) + onOffHelper.SetAttribute( + "OffTime", ns.core.StringValue("ns3::ConstantRandomVariable[Constant=0]") + ) addresses = [] nodes = [] @@ -75,18 +90,17 @@ def main(argv): else: num_nodes_side = NumNodesSide.value - nodes = ns.NodeContainer(num_nodes_side*num_nodes_side) + nodes = ns.NodeContainer(num_nodes_side * num_nodes_side) accumulator = 0 for xi in range(num_nodes_side): for yi in range(num_nodes_side): - node = nodes.Get(accumulator) accumulator += 1 container = ns.network.NodeContainer(node) internet.Install(container) mobility = ns.CreateObject("ConstantPositionMobilityModel") - mobility.SetPosition(ns.core.Vector(xi*DISTANCE, yi*DISTANCE, 0)) + mobility.SetPosition(ns.core.Vector(xi * DISTANCE, yi * DISTANCE, 0)) node.AggregateObject(mobility) device = wifi.Install(wifiPhy, wifiMac, node) @@ -95,17 +109,20 @@ def main(argv): for i, node in [(i, nodes.Get(i)) for i in range(nodes.GetN())]: destaddr = addresses[(len(addresses) - 1 - i) % len(addresses)] - #print (i, destaddr) - onOffHelper.SetAttribute("Remote", ns.network.AddressValue(ns.network.InetSocketAddress(destaddr, port).ConvertTo())) + # print (i, destaddr) + onOffHelper.SetAttribute( + "Remote", + ns.network.AddressValue(ns.network.InetSocketAddress(destaddr, port).ConvertTo()), + ) container = ns.network.NodeContainer(node) app = onOffHelper.Install(container) - urv = ns.CreateObject("UniformRandomVariable")#ns.cppyy.gbl.get_rng() + urv = ns.CreateObject("UniformRandomVariable") # ns.cppyy.gbl.get_rng() startDelay = ns.Seconds(urv.GetValue(20, 30)) app.Start(startDelay) - #internet.EnablePcapAll("wifi-olsr") + # internet.EnablePcapAll("wifi-olsr") flowmon_helper = ns.flow_monitor.FlowMonitorHelper() - #flowmon_helper.SetMonitorAttribute("StartTime", ns.core.TimeValue(ns.core.Seconds(31))) + # flowmon_helper.SetMonitorAttribute("StartTime", ns.core.TimeValue(ns.core.Seconds(31))) monitor = flowmon_helper.InstallAll() monitor = flowmon_helper.GetMonitor() monitor.SetAttribute("DelayBinWidth", ns.core.DoubleValue(0.001)) @@ -116,33 +133,60 @@ def main(argv): ns.core.Simulator.Run() def print_stats(os, st): - print (" Tx Bytes: ", st.txBytes, file=os) - print (" Rx Bytes: ", st.rxBytes, file=os) - print (" Tx Packets: ", st.txPackets, file=os) - print (" Rx Packets: ", st.rxPackets, file=os) - print (" Lost Packets: ", st.lostPackets, file=os) + print(" Tx Bytes: ", st.txBytes, file=os) + print(" Rx Bytes: ", st.rxBytes, file=os) + print(" Tx Packets: ", st.txPackets, file=os) + print(" Rx Packets: ", st.rxPackets, file=os) + print(" Lost Packets: ", st.lostPackets, file=os) if st.rxPackets > 0: - print (" Mean{Delay}: ", (st.delaySum.GetSeconds() / st.rxPackets), file=os) - print (" Mean{Jitter}: ", (st.jitterSum.GetSeconds() / (st.rxPackets-1)), file=os) - print (" Mean{Hop Count}: ", float(st.timesForwarded) / st.rxPackets + 1, file=os) + print(" Mean{Delay}: ", (st.delaySum.GetSeconds() / st.rxPackets), file=os) + print(" Mean{Jitter}: ", (st.jitterSum.GetSeconds() / (st.rxPackets - 1)), file=os) + print(" Mean{Hop Count}: ", float(st.timesForwarded) / st.rxPackets + 1, file=os) if 0: - print ("Delay Histogram", file=os) - for i in range(st.delayHistogram.GetNBins () ): - print (" ",i,"(", st.delayHistogram.GetBinStart (i), "-", \ - st.delayHistogram.GetBinEnd (i), "): ", st.delayHistogram.GetBinCount (i), file=os) - print ("Jitter Histogram", file=os) - for i in range(st.jitterHistogram.GetNBins () ): - print (" ",i,"(", st.jitterHistogram.GetBinStart (i), "-", \ - st.jitterHistogram.GetBinEnd (i), "): ", st.jitterHistogram.GetBinCount (i), file=os) - print ("PacketSize Histogram", file=os) - for i in range(st.packetSizeHistogram.GetNBins () ): - print (" ",i,"(", st.packetSizeHistogram.GetBinStart (i), "-", \ - st.packetSizeHistogram.GetBinEnd (i), "): ", st.packetSizeHistogram.GetBinCount (i), file=os) + print("Delay Histogram", file=os) + for i in range(st.delayHistogram.GetNBins()): + print( + " ", + i, + "(", + st.delayHistogram.GetBinStart(i), + "-", + st.delayHistogram.GetBinEnd(i), + "): ", + st.delayHistogram.GetBinCount(i), + file=os, + ) + print("Jitter Histogram", file=os) + for i in range(st.jitterHistogram.GetNBins()): + print( + " ", + i, + "(", + st.jitterHistogram.GetBinStart(i), + "-", + st.jitterHistogram.GetBinEnd(i), + "): ", + st.jitterHistogram.GetBinCount(i), + file=os, + ) + print("PacketSize Histogram", file=os) + for i in range(st.packetSizeHistogram.GetNBins()): + print( + " ", + i, + "(", + st.packetSizeHistogram.GetBinStart(i), + "-", + st.packetSizeHistogram.GetBinEnd(i), + "): ", + st.packetSizeHistogram.GetBinCount(i), + file=os, + ) for reason, drops in enumerate(st.packetsDropped): - print (" Packets dropped by reason %i: %i" % (reason, drops), file=os) - #for reason, drops in enumerate(st.bytesDropped): + print(" Packets dropped by reason %i: %i" % (reason, drops), file=os) + # for reason, drops in enumerate(st.bytesDropped): # print "Bytes dropped by reason %i: %i" % (reason, drops) monitor.CheckForLostPackets() @@ -151,17 +195,26 @@ def main(argv): if Results.value != b"output.xml": for flow_id, flow_stats in monitor.GetFlowStats(): t = classifier.FindFlow(flow_id) - proto = {6: 'TCP', 17: 'UDP'} [t.protocol] - print ("FlowID: %i (%s %s/%s --> %s/%i)" % \ - (flow_id, proto, t.sourceAddress, t.sourcePort, t.destinationAddress, t.destinationPort)) + proto = {6: "TCP", 17: "UDP"}[t.protocol] + print( + "FlowID: %i (%s %s/%s --> %s/%i)" + % ( + flow_id, + proto, + t.sourceAddress, + t.sourcePort, + t.destinationAddress, + t.destinationPort, + ) + ) print_stats(sys.stdout, flow_stats) else: res = monitor.SerializeToXmlFile(Results.value.decode("utf-8"), True, True) - print (res) - + print(res) if Plot.value: import pylab + delays = [] for flow_id, flow_stats in monitor.GetFlowStats(): tupl = classifier.FindFlow(flow_id) @@ -176,6 +229,5 @@ def main(argv): return 0 -if __name__ == '__main__': +if __name__ == "__main__": sys.exit(main(sys.argv)) - diff --git a/src/internet-apps/CMakeLists.txt b/src/internet-apps/CMakeLists.txt index 83b163bfa..3f6b9912a 100644 --- a/src/internet-apps/CMakeLists.txt +++ b/src/internet-apps/CMakeLists.txt @@ -3,36 +3,28 @@ build_lib( SOURCE_FILES helper/dhcp-helper.cc helper/ping-helper.cc - helper/ping6-helper.cc helper/radvd-helper.cc - helper/v4ping-helper.cc helper/v4traceroute-helper.cc model/dhcp-client.cc model/dhcp-header.cc model/dhcp-server.cc model/ping.cc - model/ping6.cc model/radvd-interface.cc model/radvd-prefix.cc model/radvd.cc - model/v4ping.cc model/v4traceroute.cc HEADER_FILES helper/dhcp-helper.h helper/ping-helper.h - helper/ping6-helper.h helper/radvd-helper.h - helper/v4ping-helper.h helper/v4traceroute-helper.h model/dhcp-client.h model/dhcp-header.h model/dhcp-server.h model/ping.h - model/ping6.h model/radvd-interface.h model/radvd-prefix.h model/radvd.h - model/v4ping.h model/v4traceroute.h LIBRARIES_TO_LINK ${libinternet} TEST_SOURCES diff --git a/src/internet-apps/helper/ping6-helper.cc b/src/internet-apps/helper/ping6-helper.cc deleted file mode 100644 index 5efccc71c..000000000 --- a/src/internet-apps/helper/ping6-helper.cc +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2008-2009 Strasbourg University - * - * 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: Sebastien Vincent - */ - -#include "ping6-helper.h" - -#include "ns3/ping6.h" -#include "ns3/uinteger.h" -#include "ns3/warnings.h" - -namespace ns3 -{ - -Ping6Helper::Ping6Helper() - : m_ifIndex(0) -{ - NS_WARNING_PUSH_DEPRECATED; - m_factory.SetTypeId(Ping6::GetTypeId()); - NS_WARNING_POP; -} - -void -Ping6Helper::SetLocal(Ipv6Address ip) -{ - m_localIp = ip; -} - -void -Ping6Helper::SetRemote(Ipv6Address ip) -{ - m_remoteIp = ip; -} - -void -Ping6Helper::SetAttribute(std::string name, const AttributeValue& value) -{ - m_factory.Set(name, value); -} - -ApplicationContainer -Ping6Helper::Install(NodeContainer c) -{ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" - - ApplicationContainer apps; - for (auto i = c.Begin(); i != c.End(); ++i) - { - Ptr node = *i; - Ptr client = m_factory.Create(); - client->SetLocal(m_localIp); - client->SetRemote(m_remoteIp); - client->SetIfIndex(m_ifIndex); - client->SetRouters(m_routers); - node->AddApplication(client); - apps.Add(client); - } - return apps; - -#pragma GCC diagnostic pop -} - -void -Ping6Helper::SetIfIndex(uint32_t ifIndex) -{ - m_ifIndex = ifIndex; -} - -void -Ping6Helper::SetRoutersAddress(std::vector routers) -{ - m_routers = routers; -} - -} /* namespace ns3 */ diff --git a/src/internet-apps/helper/ping6-helper.h b/src/internet-apps/helper/ping6-helper.h deleted file mode 100644 index 543b6bd70..000000000 --- a/src/internet-apps/helper/ping6-helper.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2008-2009 Strasbourg University - * - * 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: Sebastien Vincent - */ - -#ifndef PING6_HELPER_H -#define PING6_HELPER_H - -#include "ns3/application-container.h" -#include "ns3/ipv6-address.h" -#include "ns3/node-container.h" -#include "ns3/object-factory.h" - -#include - -namespace ns3 -{ - -/** - * \ingroup ping6 - * \brief Ping6 application helper. - */ -class Ping6Helper -{ - public: - /** - * \brief Constructor. - */ - NS_DEPRECATED_3_38("Use PingHelper instead - the attributes might have been renamed.") - Ping6Helper(); - - /** - * \brief Set the local IPv6 address. - * \param ip local IPv6 address - */ - void SetLocal(Ipv6Address ip); - - /** - * \brief Set the remote IPv6 address. - * \param ip remote IPv6 address - */ - void SetRemote(Ipv6Address ip); - - /** - * \brief Set some attributes. - * \param name attribute name - * \param value attribute value - */ - void SetAttribute(std::string name, const AttributeValue& value); - - /** - * \brief Install the application in Nodes. - * \param c list of Nodes - * \return application container - */ - ApplicationContainer Install(NodeContainer c); - - /** - * \brief Set the out interface index. - * This is to send to link-local (unicast or multicast) address - * when a node has multiple interfaces. - * \param ifIndex interface index - */ - NS_DEPRECATED_3_38("Use a source address") - void SetIfIndex(uint32_t ifIndex); - - /** - * \brief Set routers addresses for routing type 0. - * \param routers routers addresses - */ - void SetRoutersAddress(std::vector routers); - - private: - /** - * \brief An object factory. - */ - ObjectFactory m_factory; - - /** - * \brief The local IPv6 address. - */ - Ipv6Address m_localIp; - - /** - * \brief The remote IPv6 address. - */ - Ipv6Address m_remoteIp; - - /** - * \brief Out interface index. - */ - uint32_t m_ifIndex; - - /** - * \brief Routers addresses. - */ - std::vector m_routers; -}; - -} /* namespace ns3 */ - -#endif /* PING6_HELPER_H */ diff --git a/src/internet-apps/helper/v4ping-helper.cc b/src/internet-apps/helper/v4ping-helper.cc deleted file mode 100644 index d018fd8b9..000000000 --- a/src/internet-apps/helper/v4ping-helper.cc +++ /dev/null @@ -1,82 +0,0 @@ -/* - * 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 - * - * Author: Mathieu Lacage - */ - -#include "v4ping-helper.h" - -#include "ns3/names.h" -#include "ns3/v4ping.h" -#include "ns3/warnings.h" - -namespace ns3 -{ - -V4PingHelper::V4PingHelper(Ipv4Address remote) -{ - NS_WARNING_PUSH_DEPRECATED; - m_factory.SetTypeId("ns3::V4Ping"); - m_factory.Set("Remote", Ipv4AddressValue(remote)); - NS_WARNING_POP; -} - -void -V4PingHelper::SetAttribute(std::string name, const AttributeValue& value) -{ - m_factory.Set(name, value); -} - -ApplicationContainer -V4PingHelper::Install(Ptr node) const -{ - return ApplicationContainer(InstallPriv(node)); -} - -ApplicationContainer -V4PingHelper::Install(std::string nodeName) const -{ - Ptr node = Names::Find(nodeName); - return ApplicationContainer(InstallPriv(node)); -} - -ApplicationContainer -V4PingHelper::Install(NodeContainer c) const -{ - ApplicationContainer apps; - for (auto i = c.Begin(); i != c.End(); ++i) - { - apps.Add(InstallPriv(*i)); - } - - return apps; -} - -Ptr -V4PingHelper::InstallPriv(Ptr node) const -{ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" - - Ptr app = m_factory.Create(); - node->AddApplication(app); - - return app; - -#pragma GCC diagnostic pop -} - -} // namespace ns3 diff --git a/src/internet-apps/helper/v4ping-helper.h b/src/internet-apps/helper/v4ping-helper.h deleted file mode 100644 index 664f8620e..000000000 --- a/src/internet-apps/helper/v4ping-helper.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * 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 - * - * Author: Mathieu Lacage - */ - -#ifndef V4PING_HELPER_H -#define V4PING_HELPER_H - -#include "ns3/application-container.h" -#include "ns3/node-container.h" -#include "ns3/object-factory.h" - -namespace ns3 -{ - -/** - * \ingroup v4ping - * \brief Create a IPv4 ping application and associate it to a node - * - * This class creates one or multiple instances of ns3::V4Ping and associates - * it/them to one/multiple node(s). - */ -class V4PingHelper -{ - public: - /** - * Create a V4PingHelper which is used to make life easier for people wanting - * to use ping Applications. - * - * \param remote The address which should be pinged - */ - NS_DEPRECATED_3_38("Use PingHelper instead - the attributes might have been renamed.") - V4PingHelper(Ipv4Address remote); - - /** - * Install a Ping application on each Node in the provided NodeContainer. - * - * \param nodes The NodeContainer containing all of the nodes to get a V4Ping - * application. - * - * \returns A list of Ping applications, one for each input node - */ - ApplicationContainer Install(NodeContainer nodes) const; - - /** - * Install a Ping application on the provided Node. The Node is specified - * directly by a Ptr - * - * \param node The node to install the V4PingApplication on. - * - * \returns An ApplicationContainer holding the Ping application created. - */ - ApplicationContainer Install(Ptr node) const; - - /** - * Install a Ping application on the provided Node. The Node is specified - * by a string that must have previously been associated with a Node using the - * Object Name Service. - * - * \param nodeName The node to install the V4PingApplication on. - * - * \returns An ApplicationContainer holding the Ping application created. - */ - ApplicationContainer Install(std::string nodeName) const; - - /** - * \brief Configure ping applications attribute - * \param name attribute's name - * \param value attribute's value - */ - void SetAttribute(std::string name, const AttributeValue& value); - - private: - /** - * \brief Do the actual application installation in the node - * \param node the node - * \returns a Smart pointer to the installed application - */ - Ptr InstallPriv(Ptr node) const; - /// Object factory - ObjectFactory m_factory; -}; - -} // namespace ns3 - -#endif /* V4PING_HELPER_H */ diff --git a/src/internet-apps/model/dhcp-header.cc b/src/internet-apps/model/dhcp-header.cc index df9d5a603..42c382015 100644 --- a/src/internet-apps/model/dhcp-header.cc +++ b/src/internet-apps/model/dhcp-header.cc @@ -338,7 +338,7 @@ DhcpHeader::Serialize(Buffer::Iterator start) const { i.WriteU8(OP_MSGTYPE); i.WriteU8(1); - i.WriteU8((m_op + 1)); + i.WriteU8(m_op + 1); } if (m_opt[OP_ADDREQ]) { @@ -383,8 +383,8 @@ uint32_t DhcpHeader::Deserialize(Buffer::Iterator start) { uint32_t len; - uint32_t clen = start.GetSize(); - if (clen < 240) + uint32_t cLen = start.GetSize(); + if (cLen < 240) { NS_LOG_WARN("Malformed Packet"); return 0; @@ -416,7 +416,7 @@ DhcpHeader::Deserialize(Buffer::Iterator start) bool loop = true; do { - if (len + 1 <= clen) + if (len + 1 <= cLen) { option = i.ReadU8(); len += 1; @@ -429,7 +429,7 @@ DhcpHeader::Deserialize(Buffer::Iterator start) switch (option) { case OP_MASK: - if (len + 5 < clen) + if (len + 5 < cLen) { i.ReadU8(); m_mask = i.ReadNtohU32(); @@ -442,7 +442,7 @@ DhcpHeader::Deserialize(Buffer::Iterator start) } break; case OP_ROUTE: - if (len + 5 < clen) + if (len + 5 < cLen) { i.ReadU8(); ReadFrom(i, m_route); @@ -455,7 +455,7 @@ DhcpHeader::Deserialize(Buffer::Iterator start) } break; case OP_MSGTYPE: - if (len + 2 < clen) + if (len + 2 < cLen) { i.ReadU8(); m_op = (i.ReadU8() - 1); @@ -468,7 +468,7 @@ DhcpHeader::Deserialize(Buffer::Iterator start) } break; case OP_SERVID: - if (len + 5 < clen) + if (len + 5 < cLen) { i.ReadU8(); ReadFrom(i, m_dhcps); @@ -481,7 +481,7 @@ DhcpHeader::Deserialize(Buffer::Iterator start) } break; case OP_ADDREQ: - if (len + 5 < clen) + if (len + 5 < cLen) { i.ReadU8(); ReadFrom(i, m_req); @@ -494,7 +494,7 @@ DhcpHeader::Deserialize(Buffer::Iterator start) } break; case OP_LEASE: - if (len + 5 < clen) + if (len + 5 < cLen) { i.ReadU8(); m_lease = i.ReadNtohU32(); @@ -507,7 +507,7 @@ DhcpHeader::Deserialize(Buffer::Iterator start) } break; case OP_RENEW: - if (len + 5 < clen) + if (len + 5 < cLen) { i.ReadU8(); m_renew = i.ReadNtohU32(); @@ -520,7 +520,7 @@ DhcpHeader::Deserialize(Buffer::Iterator start) } break; case OP_REBIND: - if (len + 5 < clen) + if (len + 5 < cLen) { i.ReadU8(); m_rebind = i.ReadNtohU32(); diff --git a/src/internet-apps/model/ping.cc b/src/internet-apps/model/ping.cc index 96af7c094..1b2d17e71 100644 --- a/src/internet-apps/model/ping.cc +++ b/src/internet-apps/model/ping.cc @@ -69,7 +69,7 @@ Ping::GetTypeId() .AddAttribute("VerboseMode", "Configure verbose, quiet, or silent output", EnumValue(VerboseMode::VERBOSE), - MakeEnumAccessor(&Ping::m_verbose), + MakeEnumAccessor(&Ping::m_verbose), MakeEnumChecker(VerboseMode::VERBOSE, "Verbose", VerboseMode::QUIET, @@ -103,6 +103,12 @@ Ping::GetTypeId() TimeValue(Seconds(1)), MakeTimeAccessor(&Ping::m_timeout), MakeTimeChecker()) + .AddAttribute("Tos", + "The Type of Service used to send the ICMP Echo Requests. " + "All 8 bits of the TOS byte are set (including ECN bits).", + UintegerValue(0), + MakeUintegerAccessor(&Ping::m_tos), + MakeUintegerChecker()) .AddTraceSource("Tx", "The sequence number and ICMP echo response packet.", MakeTraceSourceAccessor(&Ping::m_txTrace), @@ -455,8 +461,9 @@ Ping::Send() header.EnableChecksum(); } p->AddHeader(header); - returnValue = - m_socket->SendTo(p, 0, InetSocketAddress(Ipv4Address::ConvertFrom(m_destination), 0)); + auto dest = InetSocketAddress(Ipv4Address::ConvertFrom(m_destination), 0); + dest.SetTos(m_tos); + returnValue = m_socket->SendTo(p, 0, dest); } else { diff --git a/src/internet-apps/model/ping.h b/src/internet-apps/model/ping.h index aaf80ea72..e6d23cf36 100644 --- a/src/internet-apps/model/ping.h +++ b/src/internet-apps/model/ping.h @@ -213,6 +213,8 @@ class Ping : public Application uint32_t m_size{56}; /// The socket we send packets from Ptr m_socket; + /// The Type of Service carried by ICMP ECHOs + uint8_t m_tos; /// ICMP ECHO sequence number uint16_t m_seq{0}; /// Callbacks for tracing the packet Tx events diff --git a/src/internet-apps/model/ping6.cc b/src/internet-apps/model/ping6.cc deleted file mode 100644 index a08ec697c..000000000 --- a/src/internet-apps/model/ping6.cc +++ /dev/null @@ -1,319 +0,0 @@ -/* - * Copyright (c) 2007-2009 Strasbourg University - * - * 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: Sebastien Vincent - */ - -#include "ping6.h" - -#include "ns3/icmpv6-header.h" -#include "ns3/inet6-socket-address.h" -#include "ns3/ipv6-extension-header.h" -#include "ns3/ipv6-header.h" -#include "ns3/ipv6-raw-socket-factory.h" -#include "ns3/log.h" -#include "ns3/nstime.h" -#include "ns3/packet.h" -#include "ns3/simulator.h" -#include "ns3/socket-factory.h" -#include "ns3/socket.h" -#include "ns3/uinteger.h" - -namespace ns3 -{ - -NS_LOG_COMPONENT_DEFINE("Ping6Application"); - -NS_OBJECT_ENSURE_REGISTERED(Ping6); - -TypeId -Ping6::GetTypeId() -{ - static TypeId tid = - TypeId("ns3::Ping6") - .SetParent() - .SetGroupName("Internet-Apps") - .AddConstructor() - .AddAttribute( - "MaxPackets", - "The maximum number of packets the application will send (zero means infinite)", - UintegerValue(100), - MakeUintegerAccessor(&Ping6::m_count), - MakeUintegerChecker()) - .AddAttribute("Interval", - "The time to wait between packets", - TimeValue(Seconds(1.0)), - MakeTimeAccessor(&Ping6::m_interval), - MakeTimeChecker()) - .AddAttribute("RemoteIpv6", - "The Ipv6Address of the outbound packets", - Ipv6AddressValue(), - MakeIpv6AddressAccessor(&Ping6::m_peerAddress), - MakeIpv6AddressChecker()) - .AddAttribute("LocalIpv6", - "Local Ipv6Address of the sender", - Ipv6AddressValue(), - MakeIpv6AddressAccessor(&Ping6::m_localAddress), - MakeIpv6AddressChecker()) - .AddAttribute("PacketSize", - "Size of packets generated", - UintegerValue(100), - MakeUintegerAccessor(&Ping6::m_size), - MakeUintegerChecker()); - return tid; -} - -Ping6::Ping6() -{ - NS_LOG_FUNCTION(this); - m_sent = 0; - m_socket = nullptr; - m_seq = 0; - m_ipInterfaceIndex = 0; - m_ifIndex = 0; - m_sendEvent = EventId(); -} - -Ping6::~Ping6() -{ - NS_LOG_FUNCTION(this); - m_socket = nullptr; -} - -void -Ping6::DoDispose() -{ - NS_LOG_FUNCTION(this); - Application::DoDispose(); -} - -void -Ping6::StartApplication() -{ - NS_LOG_FUNCTION(this); - - if (!m_socket) - { - TypeId tid = TypeId::LookupByName("ns3::Ipv6RawSocketFactory"); - m_socket = Socket::CreateSocket(GetNode(), tid); - - NS_ASSERT(m_socket); - - m_socket->Bind(Inet6SocketAddress(m_localAddress, 0)); - m_socket->SetAttribute("Protocol", UintegerValue(Ipv6Header::IPV6_ICMPV6)); - m_socket->SetRecvCallback(MakeCallback(&Ping6::HandleRead, this)); - m_ipv6Protocol = m_node->GetObject(); - - if (!m_localAddress.IsAny()) - { - m_ipInterfaceIndex = m_ipv6Protocol->GetInterfaceForAddress(m_localAddress); - } - } - - ScheduleTransmit(Seconds(0.)); -} - -void -Ping6::SetLocal(Ipv6Address ipv6) -{ - NS_LOG_FUNCTION(this << ipv6); - m_localAddress = ipv6; -} - -void -Ping6::SetRemote(Ipv6Address ipv6) -{ - NS_LOG_FUNCTION(this << ipv6); - m_peerAddress = ipv6; -} - -void -Ping6::StopApplication() -{ - NS_LOG_FUNCTION(this); - - if (m_socket) - { - m_socket->SetRecvCallback(MakeNullCallback>()); - } - - Simulator::Cancel(m_sendEvent); -} - -void -Ping6::SetIfIndex(uint32_t ifIndex) -{ - m_ifIndex = ifIndex; -} - -void -Ping6::ScheduleTransmit(Time dt) -{ - NS_LOG_FUNCTION(this << dt); - m_sendEvent = Simulator::Schedule(dt, &Ping6::Send, this); -} - -void -Ping6::SetRouters(std::vector routers) -{ - m_routers = routers; -} - -void -Ping6::Send() -{ - NS_LOG_FUNCTION(this); - NS_ASSERT(m_sendEvent.IsExpired()); - - Ipv6Address src; - Ptr ipv6 = GetNode()->GetObject(); - - if (m_ifIndex > 0) - { - /* hack to have ifIndex in Ipv6RawSocketImpl - * maybe add a SetIfIndex in Ipv6RawSocketImpl directly - */ - for (uint32_t i = 0; i < GetNode()->GetObject()->GetNAddresses(m_ifIndex); i++) - { - Ipv6InterfaceAddress srcIa; - srcIa = GetNode()->GetObject()->GetAddress(m_ifIndex, i); - - if (srcIa.IsInSameSubnet(m_peerAddress)) - { - src = srcIa.GetAddress(); - break; - } - } - } - else - { - src = m_localAddress; - } - - uint32_t size = m_size; - if (m_size < 4) - { - NS_LOG_WARN("ICMPv6 echo request payload size must be >= 4"); - size = 4; - } - - auto data = new uint8_t[size]; - memset(data, 0, size); - data[0] = 0xDE; - data[1] = 0xAD; - data[2] = 0xBE; - data[3] = 0xEF; - - Ptr p = Create(data, size); - Icmpv6Echo req(true); - - req.SetId(0xBEEF); - req.SetSeq(m_seq); - m_seq++; - - /* we do not calculate pseudo header checksum here, because we are not sure about - * source IPv6 address. Checksum is calculated in Ipv6RawSocketImpl. - */ - - p->AddHeader(req); - m_socket->Bind(Inet6SocketAddress(src, 0)); - - /* use Loose Routing (routing type 0) */ - if (!m_routers.empty()) - { - Ipv6ExtensionLooseRoutingHeader routingHeader; - routingHeader.SetNextHeader(Ipv6Header::IPV6_ICMPV6); - routingHeader.SetTypeRouting(0); - routingHeader.SetSegmentsLeft(m_routers.size()); - routingHeader.SetRoutersAddress(m_routers); - p->AddHeader(routingHeader); - m_socket->SetAttribute("Protocol", UintegerValue(Ipv6Header::IPV6_EXT_ROUTING)); - } - - m_socket->SendTo(p, 0, Inet6SocketAddress(m_peerAddress, 0)); - ++m_sent; - - NS_LOG_INFO("Sent " << p->GetSize() << " bytes to " << m_peerAddress); - - if (m_sent < m_count || m_count == 0) - { - ScheduleTransmit(m_interval); - } - - delete[] data; -} - -void -Ping6::HandleRead(Ptr socket) -{ - NS_LOG_FUNCTION(this << socket); - - Ptr packet = nullptr; - Address from; - while ((packet = socket->RecvFrom(from))) - { - if (Inet6SocketAddress::IsMatchingType(from)) - { - Ipv6Header hdr; - Icmpv6Echo reply(false); - Icmpv6DestinationUnreachable destUnreach; - Icmpv6TimeExceeded timeExceeded; - Inet6SocketAddress address = Inet6SocketAddress::ConvertFrom(from); - - packet->RemoveHeader(hdr); - - uint8_t type; - packet->CopyData(&type, sizeof(type)); - - switch (type) - { - case Icmpv6Header::ICMPV6_ECHO_REPLY: - packet->RemoveHeader(reply); - - NS_LOG_INFO("Received Echo Reply size = " - << std::dec << packet->GetSize() << " bytes from " << address.GetIpv6() - << " id = " << (uint16_t)reply.GetId() - << " seq = " << (uint16_t)reply.GetSeq() - << " Hop Count = " << (uint16_t)(64 - hdr.GetHopLimit())); - - if (m_ifIndex) - { - m_ipv6Protocol->ReachabilityHint(m_ifIndex, address.GetIpv6()); - } - else - { - m_ipv6Protocol->ReachabilityHint(m_ipInterfaceIndex, address.GetIpv6()); - } - - break; - case Icmpv6Header::ICMPV6_ERROR_DESTINATION_UNREACHABLE: - packet->RemoveHeader(destUnreach); - - NS_LOG_INFO("Received Destination Unreachable from " << address.GetIpv6()); - break; - case Icmpv6Header::ICMPV6_ERROR_TIME_EXCEEDED: - packet->RemoveHeader(timeExceeded); - - NS_LOG_INFO("Received Time Exceeded from " << address.GetIpv6()); - break; - default: - break; - } - } - } -} - -} /* namespace ns3 */ diff --git a/src/internet-apps/model/ping6.h b/src/internet-apps/model/ping6.h deleted file mode 100644 index 2fa2e5923..000000000 --- a/src/internet-apps/model/ping6.h +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright (c) 2007-2009 Strasbourg University - * - * 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: Sebastien Vincent - */ - -#ifndef PING6_H -#define PING6_H - -#include "ns3/application.h" -#include "ns3/ipv6-address.h" -#include "ns3/ipv6-l3-protocol.h" - -namespace ns3 -{ - -class Packet; -class Socket; - -/** - * \ingroup internet-apps - * \defgroup ping6 Ping6 - */ - -/** - * \ingroup ping6 - * \brief A ping6 application. - */ -class NS_DEPRECATED_3_38("Use Ping instead - the attributes might have been renamed.") Ping6 - : public Application -{ - public: - /** - * \brief Get the type ID. - * \return type ID - */ - static TypeId GetTypeId(); - - /** - * \brief Constructor. - */ - Ping6(); - - /** - * \brief Destructor. - */ - ~Ping6() override; - - /** - * \brief Set the local address. - * \param ipv6 the local IPv6 address - */ - void SetLocal(Ipv6Address ipv6); - - /** - * \brief Set the remote peer. - * \param ipv6 IPv6 address of the peer - */ - void SetRemote(Ipv6Address ipv6); - - /** - * \brief Set the out interface index. - * This is to send to link-local (unicast or multicast) address - * when a node has multiple interfaces. - * \param ifIndex interface index - */ - void SetIfIndex(uint32_t ifIndex); - - /** - * \brief Set routers for routing type 0 (loose routing). - * \param routers routers addresses - */ - void SetRouters(std::vector routers); - - protected: - /** - * \brief Dispose this object; - */ - void DoDispose() override; - - private: - /** - * \brief Start the application. - */ - void StartApplication() override; - - /** - * \brief Stop the application. - */ - void StopApplication() override; - - /** - * \brief Schedule sending a packet. - * \param dt interval between packet - */ - void ScheduleTransmit(Time dt); - - /** - * \brief Send a packet. - */ - void Send(); - - /** - * \brief Receive method. - * \param socket socket that receive a packet - */ - void HandleRead(Ptr socket); - - /** - * \brief Peer IPv6 address. - */ - Ipv6Address m_address; - - /** - * \brief Number of "Echo request" packets that will be sent. - */ - uint32_t m_count; - - /** - * \brief Number of packets sent. - */ - uint32_t m_sent; - - /** - * \brief Size of the packet. - */ - uint32_t m_size; - - /** - * \brief Interval between packets sent. - */ - Time m_interval; - - /** - * \brief Local address. - */ - Ipv6Address m_localAddress; - - /** - * \brief IP interface index relative to the local address. - */ - uint32_t m_ipInterfaceIndex; - - /** - * \brief IP interface index relative to the local address. - */ - Ptr m_ipv6Protocol; - - /** - * \brief Peer address. - */ - Ipv6Address m_peerAddress; - - /** - * \brief Local socket. - */ - Ptr m_socket; - - /** - * \brief Sequence number. - */ - uint16_t m_seq; - - /** - * \brief Event ID. - */ - EventId m_sendEvent; - - /** - * \brief Out interface (i.e. for link-local communication). - */ - uint32_t m_ifIndex; - - /** - * \brief Routers addresses for routing type 0. - */ - std::vector m_routers; -}; - -} /* namespace ns3 */ - -#endif /* PING6_H */ diff --git a/src/internet-apps/model/v4ping.cc b/src/internet-apps/model/v4ping.cc deleted file mode 100644 index 9a817a6d0..000000000 --- a/src/internet-apps/model/v4ping.cc +++ /dev/null @@ -1,307 +0,0 @@ -/* - * 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 - */ - -#include "v4ping.h" - -#include "ns3/assert.h" -#include "ns3/boolean.h" -#include "ns3/icmpv4.h" -#include "ns3/inet-socket-address.h" -#include "ns3/ipv4-address.h" -#include "ns3/log.h" -#include "ns3/packet.h" -#include "ns3/socket.h" -#include "ns3/trace-source-accessor.h" -#include "ns3/uinteger.h" - -namespace ns3 -{ - -NS_LOG_COMPONENT_DEFINE("V4Ping"); - -NS_OBJECT_ENSURE_REGISTERED(V4Ping); - -TypeId -V4Ping::GetTypeId() -{ - static TypeId tid = TypeId("ns3::V4Ping") - .SetParent() - .SetGroupName("Internet-Apps") - .AddConstructor() - .AddAttribute("Remote", - "The address of the machine we want to ping.", - Ipv4AddressValue(), - MakeIpv4AddressAccessor(&V4Ping::m_remote), - MakeIpv4AddressChecker()) - .AddAttribute("Verbose", - "Produce usual output.", - BooleanValue(false), - MakeBooleanAccessor(&V4Ping::m_verbose), - MakeBooleanChecker()) - .AddAttribute("Interval", - "Wait interval seconds between sending each packet.", - TimeValue(Seconds(1)), - MakeTimeAccessor(&V4Ping::m_interval), - MakeTimeChecker()) - .AddAttribute("Size", - "The number of data bytes to be sent, real packet will " - "be 8 (ICMP) + 20 (IP) bytes longer.", - UintegerValue(56), - MakeUintegerAccessor(&V4Ping::m_size), - MakeUintegerChecker(16)) - .AddTraceSource("Rtt", - "The rtt calculated by the ping.", - MakeTraceSourceAccessor(&V4Ping::m_traceRtt), - "ns3::Time::TracedCallback"); - ; - return tid; -} - -V4Ping::V4Ping() - : m_interval(Seconds(1)), - m_size(56), - m_socket(nullptr), - m_seq(0), - m_verbose(false), - m_recv(0) -{ - NS_LOG_FUNCTION(this); -} - -V4Ping::~V4Ping() -{ - NS_LOG_FUNCTION(this); -} - -void -V4Ping::DoDispose() -{ - NS_LOG_FUNCTION(this); - - if (m_next.IsRunning()) - { - StopApplication(); - } - - m_socket = nullptr; - Application::DoDispose(); -} - -uint32_t -V4Ping::GetApplicationId() const -{ - NS_LOG_FUNCTION(this); - Ptr node = GetNode(); - for (uint32_t i = 0; i < node->GetNApplications(); ++i) - { - if (node->GetApplication(i) == this) - { - return i; - } - } - NS_ASSERT_MSG(false, "forgot to add application to node"); - return 0; // quiet compiler -} - -void -V4Ping::Receive(Ptr socket) -{ - NS_LOG_FUNCTION(this << socket); - while (m_socket->GetRxAvailable() > 0) - { - Address from; - Ptr p = m_socket->RecvFrom(0xffffffff, 0, from); - NS_LOG_DEBUG("recv " << p->GetSize() << " bytes"); - NS_ASSERT(InetSocketAddress::IsMatchingType(from)); - InetSocketAddress realFrom = InetSocketAddress::ConvertFrom(from); - NS_ASSERT(realFrom.GetPort() == 1); // protocol should be icmp. - Ipv4Header ipv4; - p->RemoveHeader(ipv4); - uint32_t recvSize = p->GetSize(); - NS_ASSERT(ipv4.GetProtocol() == 1); // protocol should be icmp. - Icmpv4Header icmp; - p->RemoveHeader(icmp); - if (icmp.GetType() == Icmpv4Header::ICMPV4_ECHO_REPLY) - { - Icmpv4Echo echo; - p->RemoveHeader(echo); - auto i = m_sent.find(echo.GetSequenceNumber()); - - if (i != m_sent.end() && echo.GetIdentifier() == 0) - { - auto buf = new uint32_t[m_size]; - uint32_t dataSize = echo.GetDataSize(); - uint32_t nodeId; - uint32_t appId; - if (dataSize == m_size) - { - echo.GetData((uint8_t*)buf); - Read32((const uint8_t*)&buf[0], nodeId); - Read32((const uint8_t*)&buf[1], appId); - - if (nodeId == GetNode()->GetId() && appId == GetApplicationId()) - { - Time sendTime = i->second; - NS_ASSERT(Simulator::Now() >= sendTime); - Time delta = Simulator::Now() - sendTime; - - m_sent.erase(i); - m_avgRtt.Update(delta.GetMilliSeconds()); - m_recv++; - m_traceRtt(delta); - - if (m_verbose) - { - std::cout << recvSize << " bytes from " << realFrom.GetIpv4() << ":" - << " icmp_seq=" << echo.GetSequenceNumber() - << " ttl=" << (unsigned)ipv4.GetTtl() - << " time=" << delta.As(Time::MS) << "\n"; - } - } - } - delete[] buf; - } - } - } -} - -// Writes data to buffer in little-endian format; least significant byte -// of data is at lowest buffer address -void -V4Ping::Write32(uint8_t* buffer, const uint32_t data) -{ - NS_LOG_FUNCTION(this << (void*)buffer << data); - buffer[0] = (data >> 0) & 0xff; - buffer[1] = (data >> 8) & 0xff; - buffer[2] = (data >> 16) & 0xff; - buffer[3] = (data >> 24) & 0xff; -} - -// Writes data from a little-endian formatted buffer to data -void -V4Ping::Read32(const uint8_t* buffer, uint32_t& data) -{ - NS_LOG_FUNCTION(this << (void*)buffer << data); - data = (buffer[3] << 24) + (buffer[2] << 16) + (buffer[1] << 8) + buffer[0]; -} - -void -V4Ping::Send() -{ - NS_LOG_FUNCTION(this); - - NS_LOG_INFO("m_seq=" << m_seq); - Ptr p = Create(); - Icmpv4Echo echo; - echo.SetSequenceNumber(m_seq); - m_seq++; - echo.SetIdentifier(0); - - // - // We must write quantities out in some form of network order. Since there - // isn't an htonl to work with we just follow the convention in pcap traces - // (where any difference would show up anyway) and borrow that code. Don't - // be too surprised when you see that this is a little endian convention. - // - auto data = new uint8_t[m_size]; - for (uint32_t i = 0; i < m_size; ++i) - { - data[i] = 0; - } - NS_ASSERT(m_size >= 16); - - uint32_t tmp = GetNode()->GetId(); - Write32(&data[0 * sizeof(uint32_t)], tmp); - - tmp = GetApplicationId(); - Write32(&data[1 * sizeof(uint32_t)], tmp); - - Ptr dataPacket = Create((uint8_t*)data, m_size); - echo.SetData(dataPacket); - p->AddHeader(echo); - Icmpv4Header header; - header.SetType(Icmpv4Header::ICMPV4_ECHO); - header.SetCode(0); - if (Node::ChecksumEnabled()) - { - header.EnableChecksum(); - } - p->AddHeader(header); - m_sent.insert(std::make_pair(m_seq - 1, Simulator::Now())); - m_socket->Send(p, 0); - m_next = Simulator::Schedule(m_interval, &V4Ping::Send, this); - delete[] data; -} - -void -V4Ping::StartApplication() -{ - NS_LOG_FUNCTION(this); - - m_started = Simulator::Now(); - if (m_verbose) - { - std::cout << "PING " << m_remote << " - " << m_size << " bytes of data - " << m_size + 28 - << " bytes including ICMP and IPv4 headers.\n"; - } - - m_socket = Socket::CreateSocket(GetNode(), TypeId::LookupByName("ns3::Ipv4RawSocketFactory")); - NS_ASSERT(m_socket); - m_socket->SetAttribute("Protocol", UintegerValue(1)); // icmp - m_socket->SetRecvCallback(MakeCallback(&V4Ping::Receive, this)); - InetSocketAddress src = InetSocketAddress(Ipv4Address::GetAny(), 0); - int status; - status = m_socket->Bind(src); - NS_ASSERT(status != -1); - InetSocketAddress dst = InetSocketAddress(m_remote, 0); - status = m_socket->Connect(dst); - NS_ASSERT(status != -1); - - Send(); -} - -void -V4Ping::StopApplication() -{ - NS_LOG_FUNCTION(this); - - if (m_next.IsRunning()) - { - m_next.Cancel(); - } - if (m_socket) - { - m_socket->Close(); - } - - if (m_verbose) - { - std::ostringstream os; - os.precision(4); - os << "--- " << m_remote << " ping statistics ---\n" - << m_seq << " packets transmitted, " << m_recv << " received, " - << ((m_seq - m_recv) * 100 / m_seq) << "% packet loss, " - << "time " << (Simulator::Now() - m_started).As(Time::MS) << "\n"; - - if (m_avgRtt.Count() > 0) - { - os << "rtt min/avg/max/mdev = " << m_avgRtt.Min() << "/" << m_avgRtt.Avg() << "/" - << m_avgRtt.Max() << "/" << m_avgRtt.Stddev() << " ms\n"; - } - std::cout << os.str(); - } -} - -} // namespace ns3 diff --git a/src/internet-apps/model/v4ping.h b/src/internet-apps/model/v4ping.h deleted file mode 100644 index 86046a2f8..000000000 --- a/src/internet-apps/model/v4ping.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - * 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 - */ - -#ifndef V4PING_H -#define V4PING_H - -#include "ns3/application.h" -#include "ns3/average.h" -#include "ns3/traced-callback.h" - -#include - -namespace ns3 -{ - -class Socket; - -/** - * \ingroup internet-apps - * \defgroup v4ping V4Ping - */ - -/** - * \ingroup v4ping - * \brief an application which sends one ICMP ECHO request, waits for a REPLYs - * and reports the calculated RTT. - * - * Note: The RTT calculated is reported through a trace source. - */ -class NS_DEPRECATED_3_38("Use Ping instead - the attributes might have been renamed.") V4Ping - : public Application -{ - public: - /** - * \brief Get the type ID. - * \return the object TypeId - */ - static TypeId GetTypeId(); - - /** - * create a pinger applications - */ - V4Ping(); - ~V4Ping() override; - - private: - /** - * \brief Writes data to buffer in little-endian format. - * - * Least significant byte of data is at lowest buffer address - * - * \param buffer the buffer to write to - * \param data the data to write - */ - void Write32(uint8_t* buffer, const uint32_t data); - /** - * \brief Writes data from a little-endian formatted buffer to data. - * - * \param buffer the buffer to read from - * \param data the read data - */ - void Read32(const uint8_t* buffer, uint32_t& data); - - // inherited from Application base class. - void StartApplication() override; - void StopApplication() override; - void DoDispose() override; - /** - * \brief Return the application ID in the node. - * \returns the application id - */ - uint32_t GetApplicationId() const; - /** - * \brief Receive an ICMP Echo - * \param socket the receiving socket - * - * This function is called by lower layers through a callback. - */ - void Receive(Ptr socket); - /** - * \brief Send one Ping (ICMP ECHO) to the destination - */ - void Send(); - - /// Remote address - Ipv4Address m_remote; - /// Wait interval seconds between sending each packet - Time m_interval; - /** - * Specifies the number of data bytes to be sent. - * The default is 56, which translates into 64 ICMP data bytes when combined with the 8 bytes of - * ICMP header data. - */ - uint32_t m_size; - /// The socket we send packets from - Ptr m_socket; - /// ICMP ECHO sequence number - uint16_t m_seq; - /// TracedCallback for RTT measured by ICMP ECHOs - TracedCallback