build: more ns3 and CMake fixes
Includes: - inform ns3 user cmake was not found, or an unsupported version was found - replace open-mpi environment variables with command-line arguments - mark more variables as advanced - add -v and --verbose option to run and only output the programs output by default - fix scratch subdir prefixes and add tests - prevent cmake crash when scratch sources do not have a main function - disable MPI module by default - wrap cmakelists_content in quotes to prevent failure of filter_libraries - install pkgconfig files and add tests - pkg-config generation (still missing installation) - forward PYTHONPATH to modulegen - fix dependency search for brite, click and openflow
This commit is contained in:
@@ -73,7 +73,7 @@ option(NS3_LINK_TIME_OPTIMIZATION "Build with link-time optimization" OFF)
|
||||
option(NS3_MONOLIB
|
||||
"Build a single shared ns-3 library and link it against executables" OFF
|
||||
)
|
||||
option(NS3_MPI "Build with MPI support" ON)
|
||||
option(NS3_MPI "Build with MPI support" OFF)
|
||||
option(NS3_NATIVE_OPTIMIZATIONS "Build with -march=native -mtune=native" OFF)
|
||||
set(NS3_OUTPUT_DIRECTORY "" CACHE STRING "Directory to store built artifacts")
|
||||
option(NS3_PRECOMPILE_HEADERS
|
||||
|
||||
@@ -15,6 +15,75 @@
|
||||
#
|
||||
# Author: Gabriel Ferreira <gabrielcarvfer@gmail.com>
|
||||
|
||||
function(build_required_and_libs_lists module_name visibility libraries
|
||||
all_ns3_libraries
|
||||
)
|
||||
set(linked_libs_list)
|
||||
set(required_modules_list)
|
||||
foreach(lib ${libraries})
|
||||
if(${lib} IN_LIST all_ns3_libraries)
|
||||
get_target_property(lib_real_name ${lib} OUTPUT_NAME)
|
||||
string(REPLACE "lib" "" required_module_name ${lib})
|
||||
set(required_modules_list
|
||||
"${required_modules_list} ns3-${required_module_name}"
|
||||
)
|
||||
else()
|
||||
set(lib_real_name ${lib})
|
||||
endif()
|
||||
set(linked_libs_list "${linked_libs_list} -l${lib_real_name}")
|
||||
endforeach()
|
||||
set(pkgconfig_${visibility}_libs ${linked_libs_list} PARENT_SCOPE)
|
||||
set(pkgconfig_${visibility}_required ${required_modules_list} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(pkgconfig_module libname)
|
||||
# Fetch all libraries that will be linked to module
|
||||
get_target_property(all_libs ${libname} LINK_LIBRARIES)
|
||||
|
||||
# Then fetch public libraries
|
||||
get_target_property(interface_libs ${libname} INTERFACE_LINK_LIBRARIES)
|
||||
|
||||
# Filter linking flags
|
||||
string(REPLACE "${LIB_AS_NEEDED_PRE}" "" all_libs "${all_libs}")
|
||||
string(REPLACE "${LIB_AS_NEEDED_POST}" "" all_libs "${all_libs}")
|
||||
string(REPLACE "${LIB_AS_NEEDED_PRE}" "" interface_libs "${interface_libs}")
|
||||
string(REPLACE "${LIB_AS_NEEDED_POST}" "" interface_libs "${interface_libs}")
|
||||
|
||||
foreach(interface_lib ${interface_libs})
|
||||
list(REMOVE_ITEM all_libs ${interface_lib})
|
||||
endforeach()
|
||||
set(private_libs ${all_libs})
|
||||
|
||||
# Create two lists of publicly and privately linked libraries to this module
|
||||
string(REPLACE "lib" "" module_name ${libname})
|
||||
|
||||
# These filter out ns and non-ns libraries into public and private libraries
|
||||
# linked against module_name
|
||||
get_target_property(pkgconfig_target_lib ${libname} OUTPUT_NAME)
|
||||
|
||||
# pkgconfig_public_libs pkgconfig_public_required
|
||||
build_required_and_libs_lists(
|
||||
"${module_name}" public "${interface_libs}"
|
||||
"${ns3-libs};${ns3-contrib-libs}"
|
||||
)
|
||||
|
||||
# pkgconfig_private_libs pkgconfig_private_required
|
||||
build_required_and_libs_lists(
|
||||
"${module_name}" private "${private_libs}"
|
||||
"${ns3-libs};${ns3-contrib-libs}"
|
||||
)
|
||||
|
||||
# Configure pkgconfig file for the module using pkgconfig variables
|
||||
set(pkgconfig_file ${CMAKE_BINARY_DIR}/pkgconfig/ns3-${module_name}.pc)
|
||||
configure_file(
|
||||
${PROJECT_SOURCE_DIR}/buildsupport/pkgconfig_template.pc.in
|
||||
${pkgconfig_file} @ONLY
|
||||
)
|
||||
|
||||
# Set file to be installed
|
||||
install(FILES ${pkgconfig_file} DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
|
||||
endfunction()
|
||||
|
||||
function(ns3_cmake_package)
|
||||
# Only create configuration to export if there is an module configured to be
|
||||
# built
|
||||
@@ -27,6 +96,14 @@ function(ns3_cmake_package)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# CMake does not support '-' separated versions in config packages, so replace
|
||||
# them with dots
|
||||
string(REPLACE "-" "." ns3_version "${NS3_VER}")
|
||||
|
||||
foreach(library ${ns3-libs}${ns3-contrib-libs})
|
||||
pkgconfig_module(${library})
|
||||
endforeach()
|
||||
|
||||
install(
|
||||
EXPORT ns3ExportTargets
|
||||
NAMESPACE ns3::
|
||||
@@ -41,9 +118,6 @@ function(ns3_cmake_package)
|
||||
PATH_VARS CMAKE_INSTALL_LIBDIR
|
||||
)
|
||||
|
||||
# CMake does not support '-' separated versions in config packages, so replace
|
||||
# them with dots
|
||||
string(REPLACE "-" "." ns3_version "${NS3_VER}")
|
||||
write_basic_package_version_file(
|
||||
${CMAKE_CURRENT_BINARY_DIR}/ns3ConfigVersion.cmake VERSION ${ns3_version}
|
||||
COMPATIBILITY ExactVersion
|
||||
|
||||
@@ -16,13 +16,14 @@
|
||||
# Author: Gabriel Ferreira <gabrielcarvfer@gmail.com>
|
||||
|
||||
if(${NS3_COVERAGE})
|
||||
|
||||
mark_as_advanced(GCOVp)
|
||||
find_program(GCOVp gcov)
|
||||
if(GCOVp)
|
||||
add_definitions(--coverage)
|
||||
link_libraries(-lgcov)
|
||||
endif()
|
||||
|
||||
mark_as_advanced(LCOVp)
|
||||
find_program(LCOVp lcov)
|
||||
if(NOT LCOVp)
|
||||
message(FATAL_ERROR "LCOV is required but it is not installed.")
|
||||
|
||||
@@ -324,7 +324,8 @@ macro(
|
||||
)
|
||||
execute_process(
|
||||
COMMAND
|
||||
${CMAKE_COMMAND} -E env PYTHONPATH=${CMAKE_OUTPUT_DIRECTORY}
|
||||
${CMAKE_COMMAND} -E env
|
||||
PYTHONPATH=${CMAKE_OUTPUT_DIRECTORY}:$ENV{PYTHONPATH}
|
||||
${modulegen_modular_command} ${CMAKE_CURRENT_SOURCE_DIR} ${arch}
|
||||
${prefix}${libname_sub} ${module_src}
|
||||
TIMEOUT 60
|
||||
|
||||
@@ -66,6 +66,7 @@ function(check_ns3_closest_tags CLOSEST_TAG VERSION_TAG_DISTANCE
|
||||
endfunction()
|
||||
|
||||
function(configure_embedded_version)
|
||||
mark_as_advanced(GIT)
|
||||
find_program(GIT git)
|
||||
if(${NS3_ENABLE_BUILD_VERSION} AND (NOT GIT))
|
||||
message(FATAL_ERROR "Embedding build version into libraries require Git.")
|
||||
|
||||
@@ -256,6 +256,7 @@ function(check_deps package_deps program_deps missing_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})
|
||||
if(NOT ${upper_${program}})
|
||||
list(APPEND local_missing_deps ${program})
|
||||
@@ -1196,12 +1197,13 @@ function(recursive_dependency module_name)
|
||||
file(READ ${contrib_cmakelist} cmakelists_content)
|
||||
set(contrib TRUE)
|
||||
else()
|
||||
set(cmakelists_content "")
|
||||
message(
|
||||
STATUS "The CMakeLists.txt file for module ${module_name} was not found."
|
||||
)
|
||||
endif()
|
||||
|
||||
filter_libraries(${cmakelists_content} matches)
|
||||
filter_libraries("${cmakelists_content}" matches)
|
||||
|
||||
# Add this visited module dependencies to the dependencies list
|
||||
if(contrib)
|
||||
@@ -1389,6 +1391,51 @@ function(parse_ns3rc enabled_modules examples_enabled tests_enabled)
|
||||
endif()
|
||||
endfunction(parse_ns3rc)
|
||||
|
||||
function(find_external_library_header_and_library name header_name library_name
|
||||
search_paths
|
||||
)
|
||||
mark_as_advanced(${name}_library)
|
||||
find_library(
|
||||
${name}_library ${library_name} HINTS ${search_paths} ENV LD_LIBRARY_PATH
|
||||
PATH_SUFFIXES /build /lib /build/lib /
|
||||
)
|
||||
set(${name}_library_dir)
|
||||
if(${name}_library)
|
||||
get_filename_component(${name}_library_dir ${${name}_library} DIRECTORY
|
||||
)# e.g. lib/openflow.(so|dll|dylib|a) -> lib
|
||||
endif()
|
||||
mark_as_advanced(${name}_header)
|
||||
find_file(
|
||||
${name}_header ${header_name}
|
||||
HINTS ${search_paths} ${${name}_library_dir}/../
|
||||
${${name}_library_dir}/../../
|
||||
PATH_SUFFIXES
|
||||
/build
|
||||
/include
|
||||
/build/include
|
||||
/build/include/${name}
|
||||
/include/${name}
|
||||
/${name}
|
||||
/
|
||||
)
|
||||
# If we find both library and header, we export their values
|
||||
if(${name}_library AND ${name}_header)
|
||||
get_filename_component(header_include_dir ${${name}_header} DIRECTORY
|
||||
)# e.g. include/click/ (simclick.h) -> #include <simclick.h> should work
|
||||
get_filename_component(header_include_dir2 ${header_include_dir} DIRECTORY
|
||||
)# e.g. include/(click) -> #include <click/simclick.h> should work
|
||||
set(${name}_include_directories
|
||||
"${header_include_dir};${header_include_dir2}" PARENT_SCOPE
|
||||
)
|
||||
set(${name}_library ${${name}_library} PARENT_SCOPE)
|
||||
set(${name}_header ${${name}_header} PARENT_SCOPE)
|
||||
else()
|
||||
set(${name}_include_directories PARENT_SCOPE)
|
||||
set(${name}_library PARENT_SCOPE)
|
||||
set(${name}_header PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Waf workaround scripts
|
||||
include(buildsupport/custom_modules/waf_workaround_c4cache.cmake)
|
||||
include(buildsupport/custom_modules/waf_workaround_buildstatus.cmake)
|
||||
|
||||
13
buildsupport/pkgconfig_template.pc.in
Normal file
13
buildsupport/pkgconfig_template.pc.in
Normal file
@@ -0,0 +1,13 @@
|
||||
exec_prefix="@CMAKE_INSTALL_FULL_BINDIR@"
|
||||
libdir="@CMAKE_INSTALL_FULL_LIBDIR@"
|
||||
includedir="@CMAKE_INSTALL_FULL_INCLUDEDIR@"
|
||||
|
||||
Name: ns3-@module_name@
|
||||
Description: @CMAKE_PROJECT_DESCRIPTION@
|
||||
URL: @CMAKE_PROJECT_HOMEPAGE_URL@
|
||||
Version: @ns3_version@
|
||||
Requires: @pkgconfig_public_required@
|
||||
Requires.private: @pkgconfig_private_required@
|
||||
Cflags: -I"${includedir}"
|
||||
Libs: -L"${libdir}" -l@pkgconfig_target_lib@ @pkgconfig_public_libs@
|
||||
Libs.private: -L"${libdir}" @pkgconfig_private_libs@
|
||||
66
ns3
66
ns3
@@ -14,20 +14,20 @@ out_dir = os.sep.join([ns3_path, "build"])
|
||||
lock_file = os.sep.join([ns3_path, ".lock-waf_%s_build" % sys.platform])
|
||||
|
||||
print_buffer = ""
|
||||
run_only = False
|
||||
verbose = True
|
||||
|
||||
|
||||
# Prints everything in the print_buffer on exit
|
||||
def exit_handler(dry_run):
|
||||
global print_buffer, run_only
|
||||
# We should not print anything in run_only a.k.a. run-no-build cases, except if dry_run
|
||||
if not dry_run and run_only:
|
||||
global print_buffer, verbose
|
||||
# We should not print anything in run except if dry_run or verbose
|
||||
if not dry_run and not verbose:
|
||||
return
|
||||
if print_buffer == "":
|
||||
return
|
||||
if dry_run:
|
||||
print("The following commands would be executed:")
|
||||
elif not run_only:
|
||||
elif verbose:
|
||||
print("Finished executing the following commands:")
|
||||
print(print_buffer[1:])
|
||||
|
||||
@@ -152,7 +152,7 @@ def parse_args(argv):
|
||||
action="store_true", default=None, dest="configure_dry_run")
|
||||
|
||||
parser_clean = sub_parser.add_parser('clean', help='Removes files created by waf and ns3')
|
||||
parser_clean.add_argument('clean', action="store_true", default=False)
|
||||
parser_clean.add_argument('clean', action="store_true", default=False)
|
||||
parser_clean.add_argument('--dry-run',
|
||||
help="Do not execute the commands",
|
||||
action="store_true", default=None, dest="clean_dry_run")
|
||||
@@ -195,6 +195,10 @@ def parse_args(argv):
|
||||
help='Use sudo to setup suid bits on ns3 executables.',
|
||||
dest='enable_sudo', action='store_true',
|
||||
default=False)
|
||||
parser_run.add_argument('-v', '--verbose',
|
||||
help='Print which commands were executed',
|
||||
dest='run_verbose', action='store_true',
|
||||
default=False)
|
||||
|
||||
parser_shell = sub_parser.add_parser('shell',
|
||||
help='Try "./ns3 shell --help" for more runtime options')
|
||||
@@ -263,8 +267,8 @@ def parse_args(argv):
|
||||
args_separator_index = argv.index('--')
|
||||
args.program_args = argv[args_separator_index + 1:]
|
||||
except ValueError:
|
||||
msg = "Unknown options were given: {options}.\n"\
|
||||
"To see the allowed options add the `--help` option.\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"
|
||||
@@ -552,15 +556,31 @@ def get_program_shortcuts(build_profile, ns3_version):
|
||||
return ns3_program_map
|
||||
|
||||
|
||||
def cmake_build(current_cmake_cache_folder, output, jobs, target=None, dry_run=False):
|
||||
def parse_version(version_str):
|
||||
version = version_str.split(".")
|
||||
version = tuple(map(int, version))
|
||||
return version
|
||||
|
||||
|
||||
def cmake_check_version():
|
||||
# Check CMake version
|
||||
cmake = shutil.which("cmake")
|
||||
if not cmake:
|
||||
raise Exception("CMake was not found")
|
||||
version = re.findall("version (.*)\n", subprocess.check_output([cmake, "--version"]).decode("utf-8"))[0]
|
||||
print("Error: CMake not found; please install version 3.10 or greater, or modify $PATH")
|
||||
exit(-1)
|
||||
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))
|
||||
exit(-1)
|
||||
return cmake, version
|
||||
|
||||
|
||||
def cmake_build(current_cmake_cache_folder, output, jobs, target=None, dry_run=False):
|
||||
_, version = cmake_check_version()
|
||||
|
||||
# Older CMake versions don't accept the number of jobs directly
|
||||
jobs_part = ("-j %d" % jobs) if version >= "3.12.0" else ""
|
||||
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 = "cmake --build . %s%s" % (jobs_part, target_part)
|
||||
|
||||
@@ -653,9 +673,7 @@ def get_target_to_build(program_path, ns3_version, build_profile):
|
||||
def configuration_step(current_cmake_cache_folder, current_cmake_generator, args,
|
||||
output, dry_run=False):
|
||||
# Search for the CMake binary
|
||||
cmake = shutil.which("cmake")
|
||||
if not cmake:
|
||||
raise Exception("CMake was not found")
|
||||
cmake, _ = cmake_check_version()
|
||||
|
||||
# If --force-refresh, we load settings from the CMakeCache, delete it, then reconfigure CMake to
|
||||
# force refresh cached packages/libraries that were installed/removed, without losing the current settings
|
||||
@@ -790,9 +808,15 @@ def run_step(args, target_to_run, target_args):
|
||||
target_to_run = commands[0]
|
||||
target_args = commands[1:] + target_args
|
||||
|
||||
# running mpi on the CI?
|
||||
if target_to_run in ["mpiexec", "mpirun"] and os.getenv("MPI_CI"):
|
||||
if shutil.which("ompi_info"):
|
||||
target_args = ["--oversubscribe"] + target_args
|
||||
target_args = ["--allow-run-as-root"] + target_args
|
||||
|
||||
program_arguments = [*debugging_software, target_to_run, *target_args]
|
||||
|
||||
if not run_only or args.dry_run:
|
||||
if verbose or args.dry_run:
|
||||
exported_variables = "export "
|
||||
for (variable, value) in custom_env.items():
|
||||
if variable == "PATH":
|
||||
@@ -890,7 +914,7 @@ def refuse_run_as_root():
|
||||
|
||||
|
||||
def main():
|
||||
global out_dir, run_only
|
||||
global out_dir, verbose
|
||||
|
||||
# Refuse to run with sudo
|
||||
refuse_run_as_root()
|
||||
@@ -940,6 +964,14 @@ def main():
|
||||
run_only = False
|
||||
build_and_run = False
|
||||
if args.run:
|
||||
# When running, default to not verbose
|
||||
verbose = args.run_verbose
|
||||
|
||||
# If not verbose, silence the rest of the script
|
||||
if not verbose:
|
||||
output = subprocess.DEVNULL
|
||||
|
||||
# Check whether we are only running or we need to build first
|
||||
if not args.no_build:
|
||||
build_and_run = True
|
||||
else:
|
||||
|
||||
@@ -7,29 +7,35 @@ function(create_scratch source_files)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# If the scratch has more than a source file, we need
|
||||
# to find the source with the main function
|
||||
unset(scratch_src)
|
||||
# If the scratch has more than a source file, we need to find the source with
|
||||
# the main function
|
||||
set(scratch_src)
|
||||
foreach(source_file ${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})
|
||||
endif()
|
||||
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})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(NOT scratch_src)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Get parent directory name
|
||||
get_filename_component(scratch_dirname ${scratch_src} DIRECTORY)
|
||||
string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/" "" scratch_dirname
|
||||
${scratch_dirname}
|
||||
string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}" "" scratch_dirname
|
||||
"${scratch_dirname}"
|
||||
)
|
||||
string(REPLACE "/" "_" scratch_dirname "${scratch_dirname}")
|
||||
|
||||
# Get source name
|
||||
get_filename_component(scratch_name ${scratch_src} NAME_WE)
|
||||
|
||||
set(target_prefix scratch_)
|
||||
if(${scratch_dirname})
|
||||
if(scratch_dirname)
|
||||
# Join the names together if dirname is not the scratch folder
|
||||
set(target_prefix scratch_${scratch_dirname}_)
|
||||
set(target_prefix scratch${scratch_dirname}_)
|
||||
endif()
|
||||
|
||||
# Get source absolute path and transform into relative path
|
||||
|
||||
@@ -1,24 +1,16 @@
|
||||
set(NS3_WITH_BRITE "" CACHE PATH "Build with brite support")
|
||||
set(NS3_BRITE "OFF" CACHE INTERNAL "ON if Brite is found in NS3_WITH_BRITE")
|
||||
if(NOT NS3_WITH_BRITE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
find_library(
|
||||
brite_dep brite PATHS ${NS3_WITH_BRITE} PATH_SUFFIXES /build /build/lib /lib
|
||||
find_external_library_header_and_library(
|
||||
"brite" "Brite.h" "brite" "${NS3_WITH_BRITE}"
|
||||
)
|
||||
find_file(brite_header Brite.h HINTS ${NS3_WITH_BRITE}
|
||||
PATH_SUFFIXES /build /build/include /include
|
||||
)
|
||||
|
||||
if(NOT (brite_dep AND brite_header))
|
||||
message(STATUS "Brite was not found in ${NS3_WITH_BRITE}")
|
||||
if(NOT (brite_library AND brite_header))
|
||||
message(STATUS "Brite was not found")
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Only process module if include folder and library have been found
|
||||
get_filename_component(brite_include_folder ${brite_header} DIRECTORY)
|
||||
include_directories(${brite_include_folder})
|
||||
include_directories(${brite_include_directories})
|
||||
set(NS3_BRITE "ON" CACHE INTERNAL "ON if Brite is found in NS3_WITH_BRITE")
|
||||
|
||||
set(name brite)
|
||||
@@ -29,7 +21,7 @@ set(header_files helper/brite-topology-helper.h)
|
||||
|
||||
# link to dependencies
|
||||
set(libraries_to_link ${libnetwork} ${libcore} ${libinternet}
|
||||
${libpoint-to-point} ${brite_dep}
|
||||
${libpoint-to-point} ${brite_library}
|
||||
)
|
||||
|
||||
set(test_sources test/brite-test-topology.cc)
|
||||
|
||||
@@ -1,30 +1,15 @@
|
||||
set(NS3_WITH_CLICK "" CACHE PATH "Build with click support")
|
||||
set(NS3_CLICK "OFF" CACHE INTERNAL "ON if Click is found in NS3_WITH_CLICK")
|
||||
|
||||
if(NOT NS3_WITH_CLICK)
|
||||
find_external_library_header_and_library(
|
||||
"click" "simclick.h" "click" "${NS3_WITH_CLICK}"
|
||||
)
|
||||
if(NOT (click_library AND click_header))
|
||||
message(STATUS "Click was not found")
|
||||
return()
|
||||
endif()
|
||||
|
||||
find_library(
|
||||
click_dep click PATHS ${NS3_WITH_CLICK} PATH_SUFFIXES /build /build/lib /lib
|
||||
)
|
||||
find_file(click_header simclick.h HINTS ${NS3_WITH_CLICK}
|
||||
PATH_SUFFIXES /build /include /build/include /build/include/click
|
||||
/include/click
|
||||
)
|
||||
|
||||
if(NOT (click_dep AND click_header))
|
||||
message(STATUS "Click was not found in ${NS3_WITH_CLICK}")
|
||||
return()
|
||||
endif()
|
||||
|
||||
get_filename_component(
|
||||
openflow_header_include_folder ${openflow_header} DIRECTORY
|
||||
) # include/click/ (simclick.h)
|
||||
get_filename_component(
|
||||
openflow_header_include_folder ${openflow_header_include_folder} DIRECTORY
|
||||
) # include/(click)
|
||||
include_directories(${openflow_header_include_folder})
|
||||
include_directories(${click_include_directories})
|
||||
set(NS3_CLICK "ON" CACHE INTERNAL "ON if Click is found in NS3_WITH_CLICK")
|
||||
add_definitions(-DNS3_CLICK)
|
||||
|
||||
@@ -38,7 +23,7 @@ set(header_files helper/click-internet-stack-helper.h
|
||||
model/ipv4-click-routing.h model/ipv4-l3-click-protocol.h
|
||||
)
|
||||
|
||||
set(libraries_to_link ${libcore} ${libnetwork} ${libinternet} ${click_dep})
|
||||
set(libraries_to_link ${libcore} ${libnetwork} ${libinternet} ${click_library})
|
||||
|
||||
set(test_sources test/ipv4-click-routing-test.cc)
|
||||
|
||||
|
||||
@@ -3,31 +3,21 @@ set(NS3_OPENFLOW "OFF" CACHE INTERNAL
|
||||
"ON if Openflow is found in NS3_WITH_OPENFLOW"
|
||||
)
|
||||
|
||||
if(NOT NS3_WITH_OPENFLOW)
|
||||
find_external_library_header_and_library(
|
||||
"openflow" "openflow.h" "openflow" "${NS3_WITH_OPENFLOW}"
|
||||
)
|
||||
if(NOT (openflow_library AND openflow_header))
|
||||
message(STATUS "Openflow was not found")
|
||||
return()
|
||||
endif()
|
||||
|
||||
find_library(
|
||||
openflow_dep openflow PATHS ${NS3_WITH_OPENFLOW} PATH_SUFFIXES /build /lib
|
||||
/build/lib
|
||||
)
|
||||
find_file(openflow_header openflow.h HINTS ${NS3_WITH_OPENFLOW}
|
||||
PATH_SUFFIXES /build /include /build/include /build/include/openflow
|
||||
/include/openflow
|
||||
)
|
||||
|
||||
if(NOT (openflow_dep AND openflow_header))
|
||||
message(STATUS "Openflow was not found in ${NS3_WITH_OPENFLOW}")
|
||||
check_include_file_cxx(boost/static_assert.hpp BOOST_STATIC_ASSERT)
|
||||
if(NOT BOOST_STATIC_ASSERT)
|
||||
message(STATUS "Openflow requires Boost static_assert.hpp")
|
||||
return()
|
||||
endif()
|
||||
|
||||
get_filename_component(
|
||||
openflow_header_include_folder ${openflow_header} DIRECTORY
|
||||
) # include/openflow/ (openflow.h)
|
||||
get_filename_component(
|
||||
openflow_header_include_folder ${openflow_header_include_folder} DIRECTORY
|
||||
) # include/(openflow)
|
||||
include_directories(${openflow_header_include_folder})
|
||||
include_directories(${openflow_include_directories})
|
||||
add_definitions(-DNS3_OPENFLOW -DENABLE_OPENFLOW)
|
||||
set(NS3_OPENFLOW "ON" CACHE INTERNAL
|
||||
"ON if Openflow is found in NS3_WITH_OPENFLOW"
|
||||
@@ -43,7 +33,7 @@ set(header_files helper/openflow-switch-helper.h model/openflow-interface.h
|
||||
model/openflow-switch-net-device.h
|
||||
)
|
||||
|
||||
set(libraries_to_link ${libinternet} ${openflow_dep})
|
||||
set(libraries_to_link ${libinternet} ${openflow_library})
|
||||
|
||||
set(test_sources test/openflow-switch-test-suite.cc)
|
||||
|
||||
|
||||
@@ -225,7 +225,7 @@ class NS3RunWafTargets(unittest.TestCase):
|
||||
Try to run a different executable built by waf
|
||||
@return None
|
||||
"""
|
||||
return_code, stdout, stderr = run_ns3("run command-line-example --no-build")
|
||||
return_code, stdout, stderr = run_ns3("run command-line-example --verbose --no-build")
|
||||
self.assertEqual(return_code, 0)
|
||||
self.assertIn("command-line-example", stdout)
|
||||
|
||||
@@ -552,14 +552,14 @@ class NS3ConfigureTestCase(NS3BaseTestCase):
|
||||
@return None
|
||||
"""
|
||||
# Try filtering disabled modules to disable lte and modules that depend on it.
|
||||
return_code, stdout, stderr = run_ns3("configure --disable-modules='lte;mpi'")
|
||||
return_code, stdout, stderr = run_ns3("configure --disable-modules='lte;wimax'")
|
||||
self.config_ok(return_code, stdout)
|
||||
|
||||
# At this point we should have fewer modules.
|
||||
enabled_modules = get_enabled_modules()
|
||||
self.assertLess(len(enabled_modules), len(self.ns3_modules))
|
||||
self.assertNotIn("ns3-lte", enabled_modules)
|
||||
self.assertNotIn("ns3-mpi", enabled_modules)
|
||||
self.assertNotIn("ns3-wimax", enabled_modules)
|
||||
|
||||
# Try cleaning the list of enabled modules to reset to the normal configuration.
|
||||
return_code, stdout, stderr = run_ns3("configure --disable-modules=''")
|
||||
@@ -696,9 +696,9 @@ class NS3ConfigureTestCase(NS3BaseTestCase):
|
||||
|
||||
# Run all cases and then check outputs
|
||||
return_code0, stdout0, stderr0 = run_ns3("--dry-run run scratch-simulator")
|
||||
return_code1, stdout1, stderr1 = run_ns3("run scratch-simulator")
|
||||
return_code1, stdout1, stderr1 = run_ns3("run scratch-simulator --verbose")
|
||||
return_code2, stdout2, stderr2 = run_ns3("--dry-run run scratch-simulator --no-build")
|
||||
return_code3, stdout3, stderr3 = run_ns3("run scratch-simulator --no-build ")
|
||||
return_code3, stdout3, stderr3 = run_ns3("run scratch-simulator --no-build")
|
||||
|
||||
# Return code and stderr should be the same for all of them.
|
||||
self.assertEqual(sum([return_code0, return_code1, return_code2, return_code3]), 0)
|
||||
@@ -779,6 +779,118 @@ class NS3ConfigureTestCase(NS3BaseTestCase):
|
||||
self.assertEqual(return_code, 0)
|
||||
self.assertIn("ns-3 version:", stdout)
|
||||
|
||||
def test_13_Scratches(self):
|
||||
"""!
|
||||
Test if CMake target names for scratches and ns3 shortcuts
|
||||
are working correctly
|
||||
"""
|
||||
|
||||
test_files = ["scratch/main.cc",
|
||||
"scratch/empty.cc",
|
||||
"scratch/subdir1/main.cc",
|
||||
"scratch/subdir2/main.cc"]
|
||||
|
||||
# Create test scratch files
|
||||
for path in test_files:
|
||||
filepath = os.path.join(ns3_path, path)
|
||||
os.makedirs(os.path.dirname(filepath), exist_ok=True)
|
||||
with open(filepath, "w") as f:
|
||||
if "main" in path:
|
||||
f.write("int main (int argc, char *argv[]){}")
|
||||
else:
|
||||
# no main function will prevent this target from
|
||||
# being created, we should skip it and continue
|
||||
# processing without crashing
|
||||
f.write("")
|
||||
|
||||
# Reload the cmake cache to pick them up
|
||||
return_code, stdout, stderr = run_ns3("configure")
|
||||
self.assertEqual(return_code, 0)
|
||||
|
||||
# Try to build them with ns3 and cmake
|
||||
for path in test_files:
|
||||
path = path.replace(".cc", "")
|
||||
return_code1, stdout1, stderr1 = run_program("cmake", "--build . --target %s"
|
||||
% path.replace("/", "_"),
|
||||
cwd=os.path.join(ns3_path, "cmake_cache"))
|
||||
return_code2, stdout2, stderr2 = run_ns3("build %s" % path)
|
||||
if "main" in path:
|
||||
self.assertEqual(return_code1, 0)
|
||||
self.assertEqual(return_code2, 0)
|
||||
else:
|
||||
self.assertEqual(return_code1, 2)
|
||||
self.assertEqual(return_code2, 1)
|
||||
|
||||
# Try to run them
|
||||
for path in test_files:
|
||||
path = path.replace(".cc", "")
|
||||
return_code, stdout, stderr = run_ns3("run %s --no-build" % path)
|
||||
if "main" in path:
|
||||
self.assertEqual(return_code, 0)
|
||||
else:
|
||||
self.assertEqual(return_code, 1)
|
||||
|
||||
# Delete the test files and reconfigure to clean them up
|
||||
for path in test_files:
|
||||
source_absolute_path = os.path.join(ns3_path, path)
|
||||
os.remove(source_absolute_path)
|
||||
if "empty" in path:
|
||||
continue
|
||||
filename = os.path.basename(path).replace(".cc", "")
|
||||
executable_absolute_path = os.path.dirname(os.path.join(ns3_path, "build", path))
|
||||
executable_name = list(filter(lambda x: filename in x,
|
||||
os.listdir(executable_absolute_path)
|
||||
)
|
||||
)[0]
|
||||
|
||||
os.remove(os.path.join(executable_absolute_path, executable_name))
|
||||
if path not in ["scratch/main.cc", "scratch/empty.cc"]:
|
||||
os.rmdir(os.path.dirname(source_absolute_path))
|
||||
|
||||
return_code, stdout, stderr = run_ns3("configure")
|
||||
self.assertEqual(return_code, 0)
|
||||
|
||||
def test_14_MpiCommandTemplate(self):
|
||||
"""!
|
||||
Test if ns3 is inserting additional arguments by MPICH and OpenMPI to run on the CI
|
||||
"""
|
||||
# Skip test if mpi is not installed
|
||||
if shutil.which("mpiexec") is None:
|
||||
return
|
||||
|
||||
# Ensure sample simulator was built
|
||||
return_code, stdout, stderr = run_ns3("build sample-simulator")
|
||||
self.assertEqual(return_code, 0)
|
||||
|
||||
# Get executable path
|
||||
sample_simulator_path = list(filter(lambda x: "sample-simulator" in x, self.ns3_executables))[0]
|
||||
|
||||
mpi_command = "--dry-run run sample-simulator --command-template=\"mpiexec -np 2 %s\""
|
||||
non_mpi_command = "--dry-run run sample-simulator --command-template=\"echo %s\""
|
||||
|
||||
# Get the commands to run sample-simulator in two processes with mpi
|
||||
return_code, stdout, stderr = run_ns3(mpi_command)
|
||||
self.assertEqual(return_code, 0)
|
||||
self.assertIn("mpiexec -np 2 %s" % sample_simulator_path, stdout)
|
||||
|
||||
# Get the commands to run sample-simulator in two processes with mpi, now with the environment variable
|
||||
return_code, stdout, stderr = run_ns3(mpi_command, env={"MPI_CI": "1"})
|
||||
self.assertEqual(return_code, 0)
|
||||
if shutil.which("ompi_info"):
|
||||
self.assertIn("mpiexec --allow-run-as-root --oversubscribe -np 2 %s" % sample_simulator_path, stdout)
|
||||
else:
|
||||
self.assertIn("mpiexec --allow-run-as-root -np 2 %s" % sample_simulator_path, stdout)
|
||||
|
||||
# Now we repeat for the non-mpi command
|
||||
return_code, stdout, stderr = run_ns3(non_mpi_command)
|
||||
self.assertEqual(return_code, 0)
|
||||
self.assertIn("echo %s" % sample_simulator_path, stdout)
|
||||
|
||||
# Again the non-mpi command, with the MPI_CI environment variable set
|
||||
return_code, stdout, stderr = run_ns3(non_mpi_command, env={"MPI_CI": "1"})
|
||||
self.assertEqual(return_code, 0)
|
||||
self.assertIn("echo %s" % sample_simulator_path, stdout)
|
||||
|
||||
|
||||
class NS3BuildBaseTestCase(NS3BaseTestCase):
|
||||
"""!
|
||||
@@ -1039,47 +1151,63 @@ class NS3BuildBaseTestCase(NS3BaseTestCase):
|
||||
# specifying ns3-01 (text version with 'dev' is not supported)
|
||||
# and specifying ns3-00 (a wrong version)
|
||||
for version in ["", "3.01", "3.00"]:
|
||||
test_cmake_project = """
|
||||
cmake_minimum_required(VERSION 3.10..3.10)
|
||||
project(ns3_consumer CXX)
|
||||
find_package_import = """
|
||||
list(APPEND CMAKE_PREFIX_PATH ./{lib}/cmake/ns3)
|
||||
find_package(ns3 {version} COMPONENTS libcore)
|
||||
target_link_libraries(test PRIVATE ns3::libcore)
|
||||
""".format(lib=("lib64" if lib64 else "lib"), version=version)
|
||||
pkgconfig_import = """
|
||||
list(APPEND CMAKE_PREFIX_PATH ./)
|
||||
include(FindPkgConfig)
|
||||
pkg_check_modules(ns3 REQUIRED IMPORTED_TARGET ns3-core{version})
|
||||
target_link_libraries(test PUBLIC PkgConfig::ns3)
|
||||
""".format(lib=("lib64" if lib64 else "lib"),
|
||||
version="="+version if version else ""
|
||||
)
|
||||
|
||||
list(APPEND CMAKE_PREFIX_PATH ./{lib}/cmake/ns3)
|
||||
find_package(ns3 {version} COMPONENTS libcore)
|
||||
add_executable(test main.cpp)
|
||||
target_link_libraries(test PRIVATE ns3::libcore)
|
||||
""".format(lib=("lib64" if lib64 else "lib"), version=version)
|
||||
for import_type in [pkgconfig_import, find_package_import]:
|
||||
test_cmake_project = """
|
||||
cmake_minimum_required(VERSION 3.10..3.10)
|
||||
project(ns3_consumer CXX)
|
||||
add_executable(test main.cpp)
|
||||
""" + import_type
|
||||
|
||||
test_cmake_project_file = os.sep.join([install_prefix, "CMakeLists.txt"])
|
||||
with open(test_cmake_project_file, "w") as f:
|
||||
f.write(test_cmake_project)
|
||||
test_cmake_project_file = os.sep.join([install_prefix, "CMakeLists.txt"])
|
||||
with open(test_cmake_project_file, "w") as f:
|
||||
f.write(test_cmake_project)
|
||||
|
||||
# Configure the test project
|
||||
cmake = shutil.which("cmake")
|
||||
return_code, stdout, stderr = run_program(cmake,
|
||||
"-DCMAKE_BUILD_TYPE=debug .",
|
||||
cwd=install_prefix)
|
||||
# Configure the test project
|
||||
cmake = shutil.which("cmake")
|
||||
return_code, stdout, stderr = run_program(cmake,
|
||||
"-DCMAKE_BUILD_TYPE=debug .",
|
||||
cwd=install_prefix)
|
||||
if version == "3.00":
|
||||
self.assertEqual(return_code, 1)
|
||||
if import_type == find_package_import:
|
||||
self.assertIn('Could not find a configuration file for package "ns3" that is compatible',
|
||||
stderr.replace("\n", ""))
|
||||
elif import_type == pkgconfig_import:
|
||||
self.assertIn('A required package was not found',
|
||||
stderr.replace("\n", ""))
|
||||
else:
|
||||
raise Exception("Unknown import type")
|
||||
else:
|
||||
self.assertEqual(return_code, 0)
|
||||
self.assertIn("Build files", stdout)
|
||||
|
||||
if version == "3.00":
|
||||
self.assertEqual(return_code, 1)
|
||||
self.assertIn('Could not find a configuration file for package "ns3" that is compatible',
|
||||
stderr.replace("\n", ""))
|
||||
else:
|
||||
self.assertEqual(return_code, 0)
|
||||
self.assertIn("Build files", stdout)
|
||||
# Build the test project making use of import ns-3
|
||||
return_code, stdout, stderr = run_program("cmake", "--build .", cwd=install_prefix)
|
||||
|
||||
# Build the test project making use of import ns-3
|
||||
return_code, stdout, stderr = run_program("cmake", "--build .", cwd=install_prefix)
|
||||
if version == "3.00":
|
||||
self.assertEqual(return_code, 2)
|
||||
self.assertGreater(len(stderr), 0)
|
||||
else:
|
||||
self.assertEqual(return_code, 0)
|
||||
self.assertIn("Built target", stdout)
|
||||
|
||||
if version == "3.00":
|
||||
self.assertEqual(return_code, 2)
|
||||
self.assertGreater(len(stderr), 0)
|
||||
else:
|
||||
self.assertEqual(return_code, 0)
|
||||
self.assertIn("Built target", stdout)
|
||||
|
||||
# Try running the test program that imports ns-3
|
||||
return_code, stdout, stderr = run_program("./test", "", cwd=install_prefix)
|
||||
self.assertEqual(return_code, 0)
|
||||
# Try running the test program that imports ns-3
|
||||
return_code, stdout, stderr = run_program("./test", "", cwd=install_prefix)
|
||||
self.assertEqual(return_code, 0)
|
||||
|
||||
# Uninstall
|
||||
return_code, stdout, stderr = run_ns3("uninstall")
|
||||
@@ -1112,7 +1240,7 @@ class NS3BuildBaseTestCase(NS3BaseTestCase):
|
||||
self.assertIn(build_line, stdout)
|
||||
|
||||
# Test if run is working
|
||||
return_code, stdout, stderr = run_ns3("run %s" % target_to_run)
|
||||
return_code, stdout, stderr = run_ns3("run %s --verbose" % target_to_run)
|
||||
self.assertEqual(return_code, 0)
|
||||
self.assertIn(build_line, stdout)
|
||||
stdout = stdout.replace("scratch_%s" % target_cmake, "") # remove build lines
|
||||
@@ -1174,7 +1302,7 @@ class NS3ExpectedUseTestCase(NS3BaseTestCase):
|
||||
Try to build and run test-runner
|
||||
@return None
|
||||
"""
|
||||
return_code, stdout, stderr = run_ns3('run "test-runner --list"')
|
||||
return_code, stdout, stderr = run_ns3('run "test-runner --list" --verbose')
|
||||
self.assertEqual(return_code, 0)
|
||||
self.assertIn("Built target test-runner", stdout)
|
||||
self.assertIn(cmake_build_target_command(target="test-runner"), stdout)
|
||||
@@ -1202,7 +1330,7 @@ class NS3ExpectedUseTestCase(NS3BaseTestCase):
|
||||
Try to run test-runner without building
|
||||
@return None
|
||||
"""
|
||||
return_code, stdout, stderr = run_ns3('run "test-runner --list" --no-build ')
|
||||
return_code, stdout, stderr = run_ns3('run "test-runner --list" --no-build --verbose')
|
||||
self.assertEqual(return_code, 0)
|
||||
self.assertNotIn("Built target test-runner", stdout)
|
||||
self.assertNotIn(cmake_build_target_command(target="test-runner"), stdout)
|
||||
@@ -1230,7 +1358,7 @@ class NS3ExpectedUseTestCase(NS3BaseTestCase):
|
||||
Test if scratch simulator is executed through gdb
|
||||
@return None
|
||||
"""
|
||||
return_code, stdout, stderr = run_ns3("run scratch-simulator --gdb --no-build")
|
||||
return_code, stdout, stderr = run_ns3("run scratch-simulator --gdb --verbose --no-build")
|
||||
self.assertEqual(return_code, 0)
|
||||
self.assertIn("scratch-simulator", stdout)
|
||||
self.assertIn("No debugging symbols found", stdout)
|
||||
@@ -1240,7 +1368,7 @@ class NS3ExpectedUseTestCase(NS3BaseTestCase):
|
||||
Test if scratch simulator is executed through valgrind
|
||||
@return None
|
||||
"""
|
||||
return_code, stdout, stderr = run_ns3("run scratch-simulator --valgrind --no-build")
|
||||
return_code, stdout, stderr = run_ns3("run scratch-simulator --valgrind --verbose --no-build")
|
||||
self.assertEqual(return_code, 0)
|
||||
self.assertIn("scratch-simulator", stderr)
|
||||
self.assertIn("Memcheck", stderr)
|
||||
@@ -1445,8 +1573,8 @@ class NS3ExpectedUseTestCase(NS3BaseTestCase):
|
||||
self.assertEqual(stderr2, stderr3)
|
||||
|
||||
# Command templates with %s should at least continue and try to run the target
|
||||
return_code4, stdout4, stderr4 = run_ns3('run sample-simulator --command-template "%s --PrintVersion"')
|
||||
return_code5, stdout5, stderr5 = run_ns3('run sample-simulator --command-template="%s --PrintVersion"')
|
||||
return_code4, stdout4, _ = run_ns3('run sample-simulator --command-template "%s --PrintVersion" --verbose')
|
||||
return_code5, stdout5, _ = run_ns3('run sample-simulator --command-template="%s --PrintVersion" --verbose')
|
||||
self.assertEqual((return_code4, return_code5), (0, 0))
|
||||
self.assertIn("sample-simulator --PrintVersion", stdout4)
|
||||
self.assertIn("sample-simulator --PrintVersion", stdout5)
|
||||
@@ -1459,9 +1587,9 @@ class NS3ExpectedUseTestCase(NS3BaseTestCase):
|
||||
"""
|
||||
|
||||
# Test if all argument passing flavors are working
|
||||
return_code0, stdout0, stderr0 = run_ns3('run "sample-simulator --help"')
|
||||
return_code1, stdout1, stderr1 = run_ns3('run sample-simulator --command-template="%s --help"')
|
||||
return_code2, stdout2, stderr2 = run_ns3('run sample-simulator -- --help')
|
||||
return_code0, stdout0, stderr0 = run_ns3('run "sample-simulator --help" --verbose')
|
||||
return_code1, stdout1, stderr1 = run_ns3('run sample-simulator --command-template="%s --help" --verbose')
|
||||
return_code2, stdout2, stderr2 = run_ns3('run sample-simulator --verbose -- --help')
|
||||
|
||||
self.assertEqual((return_code0, return_code1, return_code2), (0, 0, 0))
|
||||
self.assertIn("sample-simulator --help", stdout0)
|
||||
@@ -1479,9 +1607,9 @@ class NS3ExpectedUseTestCase(NS3BaseTestCase):
|
||||
self.assertEqual(stderr1, stderr2)
|
||||
|
||||
# Now collect results for each argument individually
|
||||
return_code0, stdout0, stderr0 = run_ns3('run "sample-simulator --PrintGlobals"')
|
||||
return_code1, stdout1, stderr1 = run_ns3('run "sample-simulator --PrintGroups"')
|
||||
return_code2, stdout2, stderr2 = run_ns3('run "sample-simulator --PrintTypeIds"')
|
||||
return_code0, stdout0, stderr0 = run_ns3('run "sample-simulator --PrintGlobals" --verbose')
|
||||
return_code1, stdout1, stderr1 = run_ns3('run "sample-simulator --PrintGroups" --verbose')
|
||||
return_code2, stdout2, stderr2 = run_ns3('run "sample-simulator --PrintTypeIds" --verbose')
|
||||
|
||||
self.assertEqual((return_code0, return_code1, return_code2), (0, 0, 0))
|
||||
self.assertIn("sample-simulator --PrintGlobals", stdout0)
|
||||
@@ -1489,7 +1617,7 @@ class NS3ExpectedUseTestCase(NS3BaseTestCase):
|
||||
self.assertIn("sample-simulator --PrintTypeIds", stdout2)
|
||||
|
||||
# Then check if all the arguments are correctly merged by checking the outputs
|
||||
cmd = 'run "sample-simulator --PrintGlobals" --command-template="%s --PrintGroups" -- --PrintTypeIds'
|
||||
cmd = 'run "sample-simulator --PrintGlobals" --command-template="%s --PrintGroups" --verbose -- --PrintTypeIds'
|
||||
return_code, stdout, stderr = run_ns3(cmd)
|
||||
self.assertEqual(return_code, 0)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user