build: additional CMake and ns3 bugfixes

This commit is contained in:
Gabriel Ferreira
2021-12-16 02:29:59 +00:00
parent bb46bcce1a
commit 9d9f765ba6
8 changed files with 145 additions and 37 deletions

View File

@@ -90,6 +90,7 @@ option(NS3_SQLITE "Build with SQLite support" ON)
option(NS3_STATIC "Build a static ns-3 library and link it against executables"
OFF
)
option(NS3_VERBOSE "Print additional build system messages" OFF)
option(NS3_VISUALIZER "Build visualizer module" OFF)
option(NS3_WARNINGS "Enable compiler warnings" ON)
option(NS3_WARNINGS_AS_ERRORS

View File

@@ -27,6 +27,7 @@ macro(process_contribution contribution_list)
foreach(contribname ${contribution_list})
set(folder "contrib/${contribname}")
if(EXISTS ${PROJECT_SOURCE_DIR}/${folder}/CMakeLists.txt)
message(STATUS "Processing ${folder}")
add_subdirectory(${folder})
else()
message(

View File

@@ -44,7 +44,6 @@ macro(
#ignore_pch
)
# cmake-format: on
message(STATUS "Processing ${folder}/${libname}")
# Add library to a global list of libraries
if("${folder}" MATCHES "src")
@@ -393,6 +392,9 @@ macro(
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/
PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/ns3"
)
if(${NS3_VERBOSE})
message(STATUS "Processed ${folder}/${libname}")
endif()
endmacro()
# cmake-format: off

View File

@@ -698,6 +698,12 @@ macro(process_options)
endif()
endif()
if(${NS3_VERBOSE})
set_property(GLOBAL PROPERTY TARGET_MESSAGES TRUE)
else()
set_property(GLOBAL PROPERTY TARGET_MESSAGES OFF)
endif()
set(ENABLE_VISUALIZER FALSE)
if(${NS3_VISUALIZER})
if((NOT ${NS3_PYTHON_BINDINGS}) OR (NOT ${Python3_FOUND}))

39
ns3
View File

@@ -80,23 +80,24 @@ def parse_args(argv):
type=str, default=None)
parser_configure = on_off_argument(parser_configure, "asserts", "the asserts regardless of the compile mode")
parser_configure = on_off_argument(parser_configure, "logs", "the logs regardless of the compile mode")
parser_configure = on_off_argument(parser_configure, "tests", "the ns-3 tests")
parser_configure = on_off_argument(parser_configure, "examples", "the ns-3 examples")
parser_configure = on_off_argument(parser_configure, "static", "Build a single static library with all ns-3",
"Restore the shared libraries")
parser_configure = on_off_argument(parser_configure, "mpi", "the MPI support for distributed simulation")
parser_configure = on_off_argument(parser_configure, "des-metrics",
"Logging all events in a json file with the name of the executable "
"(which must call CommandLine::Parse(argc, argv)")
parser_configure = on_off_argument(parser_configure, "documentation", "documentation targets")
parser_configure = on_off_argument(parser_configure, "examples", "the ns-3 examples")
parser_configure = on_off_argument(parser_configure, "gcov", "code coverage analysis")
parser_configure = on_off_argument(parser_configure, "gtk", "GTK support in ConfigStore")
parser_configure = on_off_argument(parser_configure, "logs", "the logs regardless of the compile mode")
parser_configure = on_off_argument(parser_configure, "mpi", "the MPI support for distributed simulation")
parser_configure = on_off_argument(parser_configure, "tests", "the ns-3 tests")
parser_configure = on_off_argument(parser_configure, "sanitizers",
"address, memory leaks and undefined behavior sanitizers")
parser_configure = on_off_argument(parser_configure, "static", "Build a single static library with all ns-3",
"Restore the shared libraries")
parser_configure = on_off_argument(parser_configure, "verbose", "printing of additional build system messages")
parser_configure = on_off_argument(parser_configure, "warnings", "compiler warnings")
parser_configure = on_off_argument(parser_configure, "werror", "Treat compiler warnings as errors",
"Treat compiler warnings as warnings")
parser_configure = on_off_argument(parser_configure, "documentation", "documentation targets")
parser_configure = on_off_argument(parser_configure, "sanitizers",
"address, memory leaks and undefined behavior sanitizers")
parser_configure.add_argument('--enable-modules',
help='List of modules to build (e.g. core;network;internet)',
@@ -411,18 +412,19 @@ def configure_cmake(cmake, args, current_cmake_cache_folder, current_cmake_gener
cmake_args.append("-DNS3_NATIVE_OPTIMIZATIONS=%s" % on_off((args.build_profile == "optimized")))
options = (("ASSERT", "asserts"),
("LOG", "logs"),
("TESTS", "tests"),
("EXAMPLES", "examples"),
("COVERAGE", "gcov"),
("DES_METRICS", "des_metrics"),
("STATIC", "static"),
("MPI", "mpi"),
("DOCS", "documentation"),
("EXAMPLES", "examples"),
("GTK3", "gtk"),
("LOG", "logs"),
("MPI", "mpi"),
("SANITIZE", "sanitizers"),
("STATIC", "static"),
("TESTS", "tests"),
("VERBOSE", "verbose"),
("WARNINGS", "warnings"),
("WARNINGS_AS_ERRORS", "werror"),
("DOCS", "documentation"),
("SANITIZE", "sanitizers")
)
for (cmake_flag, option_name) in options:
arg = on_off_condition(args, cmake_flag, option_name)
@@ -531,7 +533,10 @@ def cmake_build(current_cmake_cache_folder, output, jobs, target=None, dry_run=F
)
)
if not dry_run:
subprocess.run(cmake_build_command.split(), cwd=current_cmake_cache_folder, stdout=output)
ret = subprocess.run(cmake_build_command.split(), cwd=current_cmake_cache_folder, stdout=output)
# In case of failure, exit prematurely with the return code from the build
if ret.returncode != 0:
exit(ret.returncode)
def extract_cmakecache_settings(current_cmake_cache_folder):

View File

@@ -2,6 +2,7 @@ set(libs "${libs_to_build}")
# Process the visualizer module first if enabled
if(${ENABLE_VISUALIZER})
message(STATUS "Processing src/visualizer")
add_subdirectory(visualizer)
list(REMOVE_ITEM libs visualizer)
endif()
@@ -9,6 +10,7 @@ endif()
# Process subdirectories
foreach(libname ${libs})
if(EXISTS ${PROJECT_SOURCE_DIR}/src/${libname}/CMakeLists.txt)
message(STATUS "Processing src/${libname}")
add_subdirectory(${libname})
else()
message(

View File

@@ -24,14 +24,17 @@ set_runtime_outputdirectory(
bench-simulator ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/utils/ ""
)
add_executable(bench-packets bench-packets.cc)
target_link_libraries(bench-packets ${libnetwork})
set_runtime_outputdirectory(
bench-packets ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/utils/ ""
)
if (network IN_LIST libs_to_build)
add_executable(bench-packets bench-packets.cc)
target_link_libraries(bench-packets ${libnetwork})
set_runtime_outputdirectory(
bench-packets ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/utils/ ""
)
add_executable(print-introspected-doxygen print-introspected-doxygen.cc)
target_link_libraries(print-introspected-doxygen ${libnetwork})
set_runtime_outputdirectory(
print-introspected-doxygen ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/utils/ ""
)
endif()
add_executable(print-introspected-doxygen print-introspected-doxygen.cc)
target_link_libraries(print-introspected-doxygen ${ns3-libs})
set_runtime_outputdirectory(
print-introspected-doxygen ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/utils/ ""
)

View File

@@ -47,11 +47,24 @@ cmake_build_target_command = partial("cmake --build . -j {jobs} --target {target
def run_ns3(args):
"""
Runs the ns3 wrapper script with arguments
:param args: string containing arguments that will get split before calling ns3
:return: tuple containing (error code, stdout and stderr)
"""
return run_program(ns3_script, args, True)
# Adapted from https://github.com/metabrainz/picard/blob/master/picard/util/__init__.py
def run_program(program, args, python=False, cwd=ns3_path):
"""
Runs a program with the given arguments and returns a tuple containing (error code, stdout and stderr)
:param program: program to execute (or python script)
:param args: string containing arguments that will get split before calling the program
:param python: flag indicating whether the program is a python script
:param cwd: working directory used that will be the root folder for the execution
:return: tuple containing (error code, stdout and stderr)
"""
if type(args) != str:
raise Exception("args should be a string")
@@ -78,6 +91,11 @@ def run_program(program, args, python=False, cwd=ns3_path):
def get_programs_list(build_status_script_path=usual_build_status_script):
"""
Extracts the programs list from build-status.py
:param build_status_script_path: path containing build-status.py
:return: list of programs
"""
values = {}
with open(build_status_script_path) as f:
exec(f.read(), globals(), values)
@@ -85,25 +103,49 @@ def get_programs_list(build_status_script_path=usual_build_status_script):
def get_libraries_list(lib_outdir=usual_lib_outdir):
"""
Gets a list of built libraries
:param lib_outdir: path containing libraries
:return: list of built libraries
"""
return glob.glob(lib_outdir + '/*', recursive=True)
def get_headers_list(outdir=usual_outdir):
"""
Gets a list of header files
:param outdir: path containing headers
:return: list of headers
"""
return glob.glob(outdir + '/**/*.h', recursive=True)
def read_c4che_entry(entry, c4cache_script_path=usual_c4che_script):
def read_c4che_entry(entry, c4che_script_path=usual_c4che_script):
"""
Read interesting entries from the c4che/_cache.py file
:param entry: entry to read from c4che/_cache.py
:param c4che_script_path: path containing _cache.py
:return: value of the requested entry
"""
values = {}
with open(c4cache_script_path) as f:
with open(c4che_script_path) as f:
exec(f.read(), globals(), values)
return values[entry]
def get_test_enabled():
"""
Check if tests are enabled in the c4che/_cache.py
:return: bool
"""
return read_c4che_entry("ENABLE_TESTS")
def get_enabled_modules():
"""
Check if tests are enabled in the c4che/_cache.py
:return: list of enabled modules (prefixed with 'ns3-')
"""
return read_c4che_entry("NS3_ENABLED_MODULES")
@@ -112,6 +154,9 @@ class NS3RunWafTargets(unittest.TestCase):
cleaned_once = False
def setUp(self):
"""
Clean the default build directory, then configure and build ns-3 with waf
"""
if not NS3RunWafTargets.cleaned_once:
NS3RunWafTargets.cleaned_once = True
run_ns3("clean")
@@ -158,6 +203,9 @@ class NS3RunWafTargets(unittest.TestCase):
class NS3CommonSettingsTestCase(unittest.TestCase):
def setUp(self):
"""
Clean configuration/build artifacts before common commands
"""
super().setUp()
# No special setup for common test cases other than making sure we are working on a clean directory
run_ns3("clean")
@@ -180,12 +228,15 @@ class NS3CommonSettingsTestCase(unittest.TestCase):
class NS3ConfigureBuildProfileTestCase(unittest.TestCase):
def setUp(self):
"""
Clean configuration/build artifacts before testing configuration settings
"""
super().setUp()
# No special setup for common test cases other than making sure we are working on a clean directory
run_ns3("clean")
def test_01_Debug(self):
return_code, stdout, stderr = run_ns3("configure -d debug")
return_code, stdout, stderr = run_ns3("configure -d debug --enable-verbose")
self.assertEqual(return_code, 0)
self.assertIn("Build profile : debug", stdout)
self.assertIn("Build files have been written to", stdout)
@@ -206,7 +257,7 @@ class NS3ConfigureBuildProfileTestCase(unittest.TestCase):
self.assertIn("Build files have been written to", stdout)
def test_03_Optimized(self):
return_code, stdout, stderr = run_ns3("configure -d optimized")
return_code, stdout, stderr = run_ns3("configure -d optimized --enable-verbose")
self.assertEqual(return_code, 0)
self.assertIn("Build profile : optimized", stdout)
self.assertIn("Build files have been written to", stdout)
@@ -236,11 +287,21 @@ class NS3BaseTestCase(unittest.TestCase):
cleaned_once = False
def config_ok(self, return_code, stdout):
"""
Check if configuration for release mode worked normally
:param return_code: return code from CMake
:param stdout: output from CMake
"""
self.assertEqual(return_code, 0)
self.assertIn("Build profile : release", stdout)
self.assertIn("Build files have been written to", stdout)
def setUp(self):
"""
Clean configuration/build artifacts before testing configuration and build settings
After configuring the build as release,
check if configuration worked and check expected output files
"""
super().setUp()
if os.path.exists(ns3rc_script):
@@ -250,7 +311,7 @@ class NS3BaseTestCase(unittest.TestCase):
if not NS3BaseTestCase.cleaned_once:
NS3BaseTestCase.cleaned_once = True
run_ns3("clean")
return_code, stdout, stderr = run_ns3("configure -d release")
return_code, stdout, stderr = run_ns3("configure -d release --enable-verbose")
self.config_ok(return_code, stdout)
# Check if build-status.py exists, then read to get list of executables
@@ -267,6 +328,9 @@ class NS3ConfigureTestCase(NS3BaseTestCase):
cleaned_once = False
def setUp(self):
"""
Reuse cleaning/release configuration from NS3BaseTestCase if flag is cleaned
"""
if not NS3ConfigureTestCase.cleaned_once:
NS3ConfigureTestCase.cleaned_once = True
NS3BaseTestCase.cleaned_once = False
@@ -455,7 +519,7 @@ class NS3ConfigureTestCase(NS3BaseTestCase):
self.assertEqual(stderr, stderr1)
# Build target before using below
run_ns3("configure -d release")
run_ns3("configure -d release --enable-verbose")
run_ns3("build scratch-simulator")
# Run all cases and then check outputs
@@ -495,6 +559,9 @@ class NS3BuildBaseTestCase(NS3BaseTestCase):
cleaned_once = False
def setUp(self):
"""
Reuse cleaning/release configuration from NS3BaseTestCase if flag is cleaned
"""
if not NS3BuildBaseTestCase.cleaned_once:
NS3BuildBaseTestCase.cleaned_once = True
NS3BaseTestCase.cleaned_once = False
@@ -525,7 +592,24 @@ class NS3BuildBaseTestCase(NS3BaseTestCase):
self.assertEqual(return_code, 0)
self.assertIn(cmake_build_project_command, stdout)
def test_05_TestVersionFile(self):
def test_05_BreakBuild(self):
# change an essential file to break the build
attribute_cc_path = os.sep.join([ns3_path, "src", "core", "model", "attribute.cc"])
attribute_cc_bak_path = attribute_cc_path + ".bak"
shutil.move(attribute_cc_path, attribute_cc_bak_path)
# build should break
return_code, stdout, stderr = run_ns3("build")
self.assertNotEqual(return_code, 0)
# move file back
shutil.move(attribute_cc_bak_path, attribute_cc_path)
# build should work again
return_code, stdout, stderr = run_ns3("build")
self.assertEqual(return_code, 0)
def test_06_TestVersionFile(self):
version_file = os.sep.join([ns3_path, "VERSION"])
with open(version_file, "w") as f:
f.write("3-00\n")
@@ -565,7 +649,7 @@ class NS3BuildBaseTestCase(NS3BaseTestCase):
# Reset flag to let it clean the build
NS3BuildBaseTestCase.cleaned_once = False
def test_06_OutputDirectory(self):
def test_07_OutputDirectory(self):
# Re-build to return to the original state
return_code, stdout, stderr = run_ns3("build")
self.ns3_libraries = get_libraries_list()
@@ -624,7 +708,7 @@ class NS3BuildBaseTestCase(NS3BaseTestCase):
for library in libraries:
self.assertTrue(os.path.exists(library))
def test_07_InstallationAndUninstallation(self):
def test_08_InstallationAndUninstallation(self):
# Remove existing libraries from the previous step
libraries = get_libraries_list()
for library in libraries:
@@ -728,6 +812,10 @@ class NS3ExpectedUseTestCase(NS3BaseTestCase):
cleaned_once = False
def setUp(self):
"""
Reuse cleaning/release configuration from NS3BaseTestCase if flag is cleaned
Here examples, tests and documentation are also enabled
"""
if not NS3ExpectedUseTestCase.cleaned_once:
NS3ExpectedUseTestCase.cleaned_once = True
NS3BaseTestCase.cleaned_once = False