build: ns3 and CMake fixes

- fix scratch shortcut transformation to build target and binary
- scan scratch files for a main function to use them as the target name
- fix CMake generator parsing
- update the -- separator message
- use -- separator to forward CMake flags from ns3
- add --vis option to ns3
- embedded version fixes
    Fix NS3_VERSION_PATCH and NS3_VERSION_RELEASE_CANDIDATE default values.
    Add check-version target to CMake.
    Add --enable-build-version to ns3.
    Add --check-profile and --check-version options to ns3.
- process each scratch subdirectory as a single target
- forward ns3 arguments after -- separator to the program to run
- fix escape sequence in command-template help string
- handle modules with very long names
This commit is contained in:
Gabriel Ferreira
2022-01-10 22:36:50 -03:00
parent 2db1e3ed8d
commit 70d11fe983
7 changed files with 399 additions and 115 deletions

View File

@@ -85,6 +85,11 @@ macro(
set(config_headers ${CMAKE_HEADER_OUTPUT_DIRECTORY}/config-store-config.h set(config_headers ${CMAKE_HEADER_OUTPUT_DIRECTORY}/config-store-config.h
${CMAKE_HEADER_OUTPUT_DIRECTORY}/core-config.h ${CMAKE_HEADER_OUTPUT_DIRECTORY}/core-config.h
) )
if(${NS3_ENABLE_BUILD_VERSION})
list(APPEND config_headers
${CMAKE_HEADER_OUTPUT_DIRECTORY}/version-defines.h
)
endif()
endif() endif()
set_target_properties( set_target_properties(
${lib${libname}} ${lib${libname}}

View File

@@ -64,3 +64,86 @@ function(check_ns3_closest_tags CLOSEST_TAG VERSION_TAG_DISTANCE
set(${VERSION_DIRTY_FLAG} 1 PARENT_SCOPE) set(${VERSION_DIRTY_FLAG} 1 PARENT_SCOPE)
endif() endif()
endfunction() endfunction()
function(configure_embedded_version)
find_program(GIT git)
if(${NS3_ENABLE_BUILD_VERSION} AND (NOT GIT))
message(FATAL_ERROR "Embedding build version into libraries require Git.")
endif()
# Check version target will not be created
if(NOT GIT)
message(
STATUS "Git was not found. Version related targets won't be enabled"
)
return()
endif()
check_git_repo_has_ns3_tags(HAS_NS3_TAGS NS3_VERSION_TAG)
if(NOT ${HAS_NS3_TAGS})
message(
FATAL_ERROR
"This repository doesn't contain ns-3 git tags to bake into the libraries."
)
endif()
check_ns3_closest_tags(
NS3_VERSION_CLOSEST_TAG NS3_VERSION_TAG_DISTANCE NS3_VERSION_COMMIT_HASH
NS3_VERSION_DIRTY_FLAG
)
set(DIRTY)
if(${NS3_VERSION_DIRTY_FLAG})
set(DIRTY "-dirty")
endif()
set(version
${NS3_VERSION_TAG}+${NS3_VERSION_TAG_DISTANCE}@${NS3_VERSION_COMMIT_HASH}${DIRTY}-${build_profile}
)
add_custom_target(check-version COMMAND echo ns-3 version: ${version})
# Split commit tag (ns-3.<minor>[.patch][-RC<digit>]) into
# (ns;3.<minor>[.patch];[-RC<digit>]):
string(REPLACE "-" ";" NS3_VER_LIST ${NS3_VERSION_TAG})
list(LENGTH NS3_VER_LIST NS3_VER_LIST_LEN)
# Get last version tag fragment (RC<digit>)
set(RELEASE_CANDIDATE " ")
if(${NS3_VER_LIST_LEN} GREATER 2)
list(GET NS3_VER_LIST 2 RELEASE_CANDIDATE)
endif()
# Get 3.<minor>[.patch]
list(GET NS3_VER_LIST 1 VERSION_STRING)
# Split into a list 3;<minor>[;patch]
string(REPLACE "." ";" VERSION_LIST ${VERSION_STRING})
list(LENGTH VERSION_LIST VER_LIST_LEN)
list(GET VERSION_LIST 0 NS3_VERSION_MAJOR)
if(${VER_LIST_LEN} GREATER 1)
list(GET VERSION_LIST 1 NS3_VERSION_MINOR)
if(${VER_LIST_LEN} GREATER 2)
list(GET VERSION_LIST 2 NS3_VERSION_PATCH)
else()
set(NS3_VERSION_PATCH "00")
endif()
endif()
# Transform list with 1 entry into strings
set(NS3_VERSION_MAJOR "${NS3_VERSION_MAJOR}")
set(NS3_VERSION_MINOR "${NS3_VERSION_MINOR}")
set(NS3_VERSION_PATCH "${NS3_VERSION_PATCH}")
set(NS3_VERSION_TAG "${NS3_VERSION_TAG}")
set(NS3_VERSION_RELEASE_CANDIDATE "${RELEASE_CANDIDATE}")
set(NS3_VERSION_BUILD_PROFILE ${cmakeBuildType})
# Enable embedding build version
if(${NS3_ENABLE_BUILD_VERSION})
add_definitions(-DENABLE_BUILD_VERSION=1)
configure_file(
buildsupport/version-defines-template.h
${CMAKE_HEADER_OUTPUT_DIRECTORY}/version-defines.h
)
endif()
endfunction()

View File

@@ -74,10 +74,17 @@ function(print_formatted_table_with_modules table_name modules output)
set(width 26) # Variable with column width set(width 26) # Variable with column width
string(REPLACE "lib" "" modules_to_print "${modules}") string(REPLACE "lib" "" modules_to_print "${modules}")
list(SORT modules_to_print) # Sort for nice output list(SORT modules_to_print) # Sort for nice output
set(modules_with_large_names)
foreach(module ${modules_to_print}) foreach(module ${modules_to_print})
# Get the size of the module string name # Get the size of the module string name
string(LENGTH ${module} module_name_length) string(LENGTH ${module} module_name_length)
# Skip modules with names wider than 26 characters
if(${module_name_length} GREATER_EQUAL ${width})
list(APPEND modules_with_large_names ${module})
continue()
endif()
# Calculate trailing spaces to fill the column # Calculate trailing spaces to fill the column
math(EXPR num_trailing_spaces "${width} - ${module_name_length}") math(EXPR num_trailing_spaces "${width} - ${module_name_length}")
@@ -94,7 +101,13 @@ function(print_formatted_table_with_modules table_name modules output)
set(count 0) set(count 0)
endif() endif()
endforeach() endforeach()
# Print modules with large names one by one
foreach(module ${modules_with_large_names})
string(APPEND temp "${module}\n")
endforeach()
string(APPEND temp "\n") string(APPEND temp "\n")
# Save the table outer scope out variable # Save the table outer scope out variable
set(${output} ${${output}}${temp} PARENT_SCOPE) set(${output} ${${output}}${temp} PARENT_SCOPE)
endfunction() endfunction()

View File

@@ -326,68 +326,8 @@ macro(process_options)
endif() endif()
endif() endif()
if(${NS3_ENABLE_BUILD_VERSION}) include(buildsupport/custom_modules/ns3_versioning.cmake)
include(buildsupport/custom_modules/ns3_versioning.cmake) configure_embedded_version()
add_definitions(-DENABLE_BUILD_VERSION=1)
find_program(GIT git)
if(NOT GIT)
message(FATAL_ERROR "Baking build version into libraries require Git.")
endif()
check_git_repo_has_ns3_tags(HAS_NS3_TAGS NS3_VERSION_TAG)
if(NOT ${HAS_NS3_TAGS})
message(
FATAL_ERROR
"This repository doesn't contain ns-3 git tags to bake into the libraries."
)
endif()
check_ns3_closest_tags(
NS3_VERSION_CLOSEST_TAG NS3_VERSION_TAG_DISTANCE NS3_VERSION_COMMIT_HASH
NS3_VERSION_DIRTY_FLAG
)
# Split commit tag (ns-3.<minor>[.patch][-RC<digit>]) into
# (ns;3.<minor>[.patch];[-RC<digit>]):
string(REPLACE "-" ";" NS3_VER_LIST ${NS3_VERSION_TAG})
list(LENGTH NS3_VER_LIST NS3_VER_LIST_LEN)
# Get last version tag fragment (RC<digit>)
set(NS3_VERSION_RELEASE_CANDIDATE)
if(${NS3_VER_LIST_LEN} GREATER 2)
list(GET NS3_VER_LIST 2 RELEASE_CANDIDATE)
set(NS3_VERSION_RELEASE_CANDIDATE "${RELEASE_CANDIDATE}")
endif()
# Get 3.<minor>[.patch]
list(GET NS3_VER_LIST 1 VERSION_STRING)
# Split into a list 3;<minor>[;patch]
string(REPLACE "." ";" VERSION_LIST ${VERSION_STRING})
list(LENGTH VERSION_LIST VER_LIST_LEN)
list(GET VERSION_LIST 0 NS3_VERSION_MAJOR)
if(${VER_LIST_LEN} GREATER 1)
list(GET VERSION_LIST 1 NS3_VERSION_MINOR)
if(${VER_LIST_LEN} GREATER 2)
list(GET VERSION_LIST 2 NS3_VERSION_PATCH)
endif()
endif()
# Transform list with 1 entry into strings
set(NS3_VERSION_MAJOR "${NS3_VERSION_MAJOR}")
set(NS3_VERSION_MINOR "${NS3_VERSION_MINOR}")
set(NS3_VERSION_PATCH "${NS3_VERSION_PATCH}")
set(NS3_VERSION_TAG "${NS3_VERSION_TAG}")
# Set
set(NS3_VERSION_BUILD_PROFILE ${cmakeBuildType})
configure_file(
buildsupport/version-defines-template.h
${CMAKE_HEADER_OUTPUT_DIRECTORY}/version-defines.h
)
endif()
if(${NS3_CLANG_FORMAT}) if(${NS3_CLANG_FORMAT})
find_program(CLANG_FORMAT clang-format) find_program(CLANG_FORMAT clang-format)

97
ns3
View File

@@ -72,8 +72,7 @@ def parse_args(argv):
parser_configure = sub_parser.add_parser('configure', parser_configure = sub_parser.add_parser('configure',
help='Try "./ns3 configure --help" for more configuration options') help='Try "./ns3 configure --help" for more configuration options')
parser_configure.add_argument('configure', parser_configure.add_argument('configure',
nargs='?', action='store_true', default=False)
action='store', default=True)
parser_configure.add_argument('-d', '--build-profile', parser_configure.add_argument('-d', '--build-profile',
help='Build profile', help='Build profile',
dest='build_profile', dest='build_profile',
@@ -93,6 +92,8 @@ def parse_args(argv):
parser_configure = on_off_argument(parser_configure, "des-metrics", parser_configure = on_off_argument(parser_configure, "des-metrics",
"Logging all events in a json file with the name of the executable " "Logging all events in a json file with the name of the executable "
"(which must call CommandLine::Parse(argc, argv)") "(which must call CommandLine::Parse(argc, argv)")
parser_configure = on_off_argument(parser_configure, "build-version",
"embedding git changes as a build version during build")
parser_configure = on_off_argument(parser_configure, "examples", "the ns-3 examples") 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, "gcov", "code coverage analysis")
parser_configure = on_off_argument(parser_configure, "gtk", "GTK support in ConfigStore") parser_configure = on_off_argument(parser_configure, "gtk", "GTK support in ConfigStore")
@@ -151,21 +152,16 @@ def parse_args(argv):
action="store_true", default=None, dest="configure_dry_run") 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 = sub_parser.add_parser('clean', help='Removes files created by waf and ns3')
parser_clean.add_argument('clean', parser_clean.add_argument('clean', action="store_true", default=False)
nargs="?",
action="store", default=True)
parser_clean.add_argument('--dry-run', parser_clean.add_argument('--dry-run',
help="Do not execute the commands", help="Do not execute the commands",
action="store_true", default=None, dest="clean_dry_run") action="store_true", default=None, dest="clean_dry_run")
parser_install = sub_parser.add_parser('install', help='Install ns-3') parser_install = sub_parser.add_parser('install', help='Install ns-3')
parser_install.add_argument('install', parser_install.add_argument('install', action="store_true", default=False)
nargs="?",
action="store", default=True)
parser_uninstall = sub_parser.add_parser('uninstall', help='Uninstall ns-3') parser_uninstall = sub_parser.add_parser('uninstall', help='Uninstall ns-3')
parser_uninstall.add_argument('uninstall', parser_uninstall.add_argument('uninstall', action="store_true", default=False)
nargs="?",
action="store", default=True)
parser_run = sub_parser.add_parser('run', parser_run = sub_parser.add_parser('run',
help='Try "./ns3 run --help" for more runtime options') help='Try "./ns3 run --help" for more runtime options')
@@ -177,7 +173,7 @@ def parse_args(argv):
action="store_true", default=False) action="store_true", default=False)
parser_run.add_argument('--command-template', parser_run.add_argument('--command-template',
help=('Template of the command used to run the program given by run;' help=('Template of the command used to run the program given by run;'
' It should be a shell command string containing %s inside,' ' It should be a shell command string containing %%s inside,'
' which will be replaced by the actual program.'), ' which will be replaced by the actual program.'),
type=str, default=None) type=str, default=None)
parser_run.add_argument('--cwd', parser_run.add_argument('--cwd',
@@ -189,9 +185,9 @@ def parse_args(argv):
parser_run.add_argument('--valgrind', parser_run.add_argument('--valgrind',
help='Change the default command template to run programs with valgrind', help='Change the default command template to run programs with valgrind',
action="store_true", default=None) action="store_true", default=None)
parser_run.add_argument('--visualize', parser_run.add_argument('--vis', '--visualize',
help='Modify --run arguments to enable the visualizer', help='Modify --run arguments to enable the visualizer',
action="store_true", default=None) action="store_true", dest="visualize", default=None)
parser_run.add_argument('--dry-run', parser_run.add_argument('--dry-run',
help="Do not execute the commands", help="Do not execute the commands",
action="store_true", default=None, dest="run_dry_run") action="store_true", default=None, dest="run_dry_run")
@@ -203,9 +199,8 @@ def parse_args(argv):
parser_shell = sub_parser.add_parser('shell', parser_shell = sub_parser.add_parser('shell',
help='Try "./ns3 shell --help" for more runtime options') help='Try "./ns3 shell --help" for more runtime options')
parser_shell.add_argument('shell', parser_shell.add_argument('shell',
nargs="?",
help='Export necessary environment variables and open a shell', help='Export necessary environment variables and open a shell',
action="store", default=True) action="store_true", default=False)
parser_docs = sub_parser.add_parser('docs', parser_docs = sub_parser.add_parser('docs',
help='Try "./ns3 docs --help" for more documentation options') help='Try "./ns3 docs --help" for more documentation options')
@@ -231,6 +226,12 @@ def parse_args(argv):
parser.add_argument('--check', parser.add_argument('--check',
help='DEPRECATED (run ./test.py)', help='DEPRECATED (run ./test.py)',
action='store_true', default=None) action='store_true', default=None)
parser.add_argument('--check-profile',
help='Print out current build profile',
action='store_true', default=None)
parser.add_argument('--check-version',
help='Print the current build version',
action='store_true', default=None)
# parser.add_argument('--docset', # parser.add_argument('--docset',
# help=( # help=(
@@ -239,7 +240,8 @@ def parse_args(argv):
# action="store_true", default=None, # action="store_true", default=None,
# dest="docset_build") # dest="docset_build")
args = parser.parse_args(argv) # Parse known arguments and separate from unknown arguments
args, unknown_args = parser.parse_known_args(argv)
# Merge dry_runs # Merge dry_runs
dry_run_args = [(args.__getattribute__(name) if name in args else None) for name in dry_run_args = [(args.__getattribute__(name) if name in args else None) for name in
@@ -253,6 +255,23 @@ def parse_args(argv):
if args.run and args.enable_sudo is None: if args.run and args.enable_sudo is None:
args.enable_sudo = True args.enable_sudo = True
# Filter arguments before --
setattr(args, "program_args", [])
if unknown_args:
try:
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"\
"To forward configuration or runtime options, put them after '--'.\n"
if args.run:
msg += "Try: ./ns3 run {target} -- {options}\n"
if args.configure:
msg += "Try: ./ns3 configure -- {options}\n"
msg = msg.format(options=", ".join(unknown_args), target=args.run)
raise Exception(msg)
return args return args
@@ -337,7 +356,7 @@ def search_cmake_cache(build_profile):
current_cmake_cache_folder = os.path.dirname(cmake_cache_file) current_cmake_cache_folder = os.path.dirname(cmake_cache_file)
# Check the generator # Check the generator
if "CMAKE_GENERATOR" in line: if "CMAKE_GENERATOR:" in line:
current_cmake_generator = line.split("=")[-1] current_cmake_generator = line.split("=")[-1]
if not current_cmake_generator: if not current_cmake_generator:
@@ -360,12 +379,17 @@ def search_cmake_cache(build_profile):
return current_cmake_cache_folder, current_cmake_generator return current_cmake_cache_folder, current_cmake_generator
def project_not_configured(config_msg=""):
print("You need to configure ns-3 first: try ./ns3 configure%s" % config_msg)
exit(1)
def check_config(current_cmake_cache_folder): def check_config(current_cmake_cache_folder):
if current_cmake_cache_folder is None: if current_cmake_cache_folder is None:
raise Exception("Project was not configured") project_not_configured()
waf_like_config_table = current_cmake_cache_folder + os.sep + "ns3wafconfig.txt" waf_like_config_table = current_cmake_cache_folder + os.sep + "ns3wafconfig.txt"
if not os.path.exists(waf_like_config_table): if not os.path.exists(waf_like_config_table):
raise Exception("Project was not configured") project_not_configured()
with open(waf_like_config_table, "r") as f: with open(waf_like_config_table, "r") as f:
print(f.read()) print(f.read())
@@ -419,6 +443,7 @@ def configure_cmake(cmake, args, current_cmake_cache_folder, current_cmake_gener
options = (("ASSERT", "asserts"), options = (("ASSERT", "asserts"),
("COVERAGE", "gcov"), ("COVERAGE", "gcov"),
("DES_METRICS", "des_metrics"), ("DES_METRICS", "des_metrics"),
("ENABLE_BUILD_VERSION", "build_version"),
("ENABLE_SUDO", "sudo"), ("ENABLE_SUDO", "sudo"),
("EXAMPLES", "examples"), ("EXAMPLES", "examples"),
("GTK3", "gtk"), ("GTK3", "gtk"),
@@ -468,6 +493,9 @@ def configure_cmake(cmake, args, current_cmake_cache_folder, current_cmake_gener
cmake_args.append("-G") cmake_args.append("-G")
cmake_args.append(args.G) cmake_args.append(args.G)
# Append CMake flags passed using the -- separator
cmake_args.extend(args.program_args)
# Configure cmake # Configure cmake
cmake_args.append("..") # for now, assuming the cmake_cache directory is inside the ns-3-dev folder cmake_args.append("..") # for now, assuming the cmake_cache directory is inside the ns-3-dev folder
@@ -502,6 +530,11 @@ def get_program_shortcuts(build_profile, ns3_version):
# Remove version prefix and build type suffix from shortcuts (or keep them too?) # 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:
subdir = "_".join([*temp_path[2:-1], ""])
temp_path[-1] = temp_path[-1].replace(subdir, "")
# Check if there is a .cc file for that specific program # Check if there is a .cc file for that specific program
source_file_path = os.sep.join(temp_path) + ".cc" source_file_path = os.sep.join(temp_path) + ".cc"
source_shortcut = False source_shortcut = False
@@ -611,7 +644,7 @@ def get_target_to_build(program_path, ns3_version, build_profile):
if "scratch" in program_path: if "scratch" in program_path:
# Get the path to the program and replace slashes with underlines # Get the path to the program and replace slashes with underlines
# to get unique targets for CMake, preventing collisions with modules examples # to get unique targets for CMake, preventing collisions with modules examples
return program_name.split(out_dir + "/")[1].replace("/", "_") return program_name.replace(out_dir, "").replace("/", "_")[1:]
else: else:
# Other programs just use their normal names (without version prefix and build_profile suffix) as targets # Other programs just use their normal names (without version prefix and build_profile suffix) as targets
return program_name.split("/")[-1] return program_name.split("/")[-1]
@@ -661,7 +694,9 @@ def build_step(args,
# If we are building specific targets, we build them one by one # If we are building specific targets, we build them one by one
if "build" in args: if "build" in args:
non_executable_targets = ["docs", non_executable_targets = ["check-version",
"cmake-format",
"docs",
"doxygen", "doxygen",
"doxygen-no-build", "doxygen-no-build",
"sphinx", "sphinx",
@@ -670,7 +705,7 @@ def build_step(args,
"tutorial", "tutorial",
"install", "install",
"uninstall", "uninstall",
"cmake-format"] ]
# Build targets in the list # Build targets in the list
for target in args.build: for target in args.build:
if target in ns3_modules: if target in ns3_modules:
@@ -723,6 +758,7 @@ def run_step(args, target_to_run, target_args):
debugging_software = [] debugging_software = []
working_dir = ns3_path working_dir = ns3_path
use_shell = False use_shell = False
target_args += args.program_args
# running test.py/check? # running test.py/check?
if args.check: if args.check:
@@ -893,6 +929,15 @@ def main():
# Get build profile # Get build profile
build_profile, ns3_version, ns3_modules, enable_sudo = check_build_profile(out_dir) build_profile, ns3_version, ns3_modules, enable_sudo = check_build_profile(out_dir)
if args.check_profile:
if build_profile:
print("Build profile: %s" % build_profile)
else:
project_not_configured()
if args.check_version:
args.build = ["check-version"]
# Check if running something or reconfiguring ns-3 # Check if running something or reconfiguring ns-3
run_only = False run_only = False
build_and_run = False build_and_run = False
@@ -934,8 +979,10 @@ def main():
) )
if not project_configured(current_cmake_cache_folder): if not project_configured(current_cmake_cache_folder):
print("You need to configure ns-3 first: try ./ns3 configure") project_not_configured()
exit(0)
if ns3_modules is None:
project_not_configured()
# We could also replace the "ns3-" prefix used in c4che with the "lib" prefix currently used in cmake # We could also replace the "ns3-" prefix used in c4che with the "lib" prefix currently used in cmake
ns3_modules = [module.replace("ns3-", "") for module in ns3_modules] ns3_modules = [module.replace("ns3-", "") for module in ns3_modules]

View File

@@ -1,36 +1,78 @@
file(GLOB_RECURSE scratches ${CMAKE_CURRENT_SOURCE_DIR}/*.cc)
set(DONT_BUILD)
set(target_prefix scratch_) set(target_prefix scratch_)
foreach(scratch_src ${scratches}) function(create_scratch source_files)
# Get source filename without path or extension # Return early if no sources in the subdirectory
get_filename_component(scratch_name ${scratch_src} NAME) list(LENGTH source_files number_sources)
string(REGEX REPLACE "\\.[^.]*$" "" scratch_name ${scratch_name}) if(number_sources EQUAL 0)
return()
endif()
# If the scratch has more than a source file, we need
# to find the source with the main function
unset(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()
endforeach()
# Get parent directory name
get_filename_component(scratch_dirname ${scratch_src} DIRECTORY)
string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/" "" scratch_dirname
${scratch_dirname}
)
# Get source name
get_filename_component(scratch_name ${scratch_src} NAME_WE)
set(target_prefix scratch_)
if(${scratch_dirname})
# Join the names together if dirname is not the scratch folder
set(target_prefix scratch_${scratch_dirname}_)
endif()
# Get source absolute path and transform into relative path # Get source absolute path and transform into relative path
get_filename_component(scratch_absolute_directory ${scratch_src} DIRECTORY) get_filename_component(scratch_absolute_directory ${scratch_src} DIRECTORY)
string(REPLACE "${PROJECT_SOURCE_DIR}" "${CMAKE_OUTPUT_DIRECTORY}" string(REPLACE "${PROJECT_SOURCE_DIR}" "${CMAKE_OUTPUT_DIRECTORY}"
scratch_directory ${scratch_absolute_directory} scratch_directory ${scratch_absolute_directory}
) )
add_executable(${target_prefix}${scratch_name} "${source_files}")
# Build scratch if not listed as a DONT_BUILD if(${NS3_STATIC})
string(FIND "${DONT_BUILD}" "${scratch_name}" res) target_link_libraries(
if(res LESS 0) ${target_prefix}${scratch_name} ${LIB_AS_NEEDED_PRE_STATIC}
add_executable(${target_prefix}${scratch_name} "${scratch_src}") ${lib-ns3-static}
if(${NS3_STATIC}) )
target_link_libraries( else()
${target_prefix}${scratch_name} ${LIB_AS_NEEDED_PRE_STATIC} target_link_libraries(
${lib-ns3-static} ${target_prefix}${scratch_name} "${ns3-libs}" "${ns3-contrib-libs}"
) "${ns3-external-libs}"
else()
target_link_libraries(
${target_prefix}${scratch_name} "${ns3-libs}" "${ns3-contrib-libs}"
"${ns3-external-libs}"
)
endif()
set_runtime_outputdirectory(
${scratch_name} ${scratch_directory}/ ${target_prefix}
) )
endif() endif()
set_runtime_outputdirectory(
${scratch_name} ${scratch_directory}/ ${target_prefix}
)
endfunction()
# Scan *.cc files in ns-3-dev/scratch and build a target for each
file(GLOB single_source_file_scratches ${CMAKE_CURRENT_SOURCE_DIR}/*.cc)
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
file(GLOB_RECURSE scratch_subdirectories LIST_DIRECTORIES true
${CMAKE_CURRENT_SOURCE_DIR}/**
)
# Filter out files
foreach(entry ${scratch_subdirectories})
if(NOT (IS_DIRECTORY ${entry}))
list(REMOVE_ITEM scratch_subdirectories ${entry})
endif()
endforeach()
foreach(subdir ${scratch_subdirectories})
file(GLOB scratch_sources ${subdir}/*.cc)
create_scratch("${scratch_sources}")
endforeach() endforeach()

View File

@@ -288,7 +288,7 @@ class NS3CommonSettingsTestCase(unittest.TestCase):
@return None @return None
""" """
return_code, stdout, stderr = run_ns3("") return_code, stdout, stderr = run_ns3("")
self.assertEqual(return_code, 0) self.assertEqual(return_code, 1)
self.assertIn("You need to configure ns-3 first: try ./ns3 configure", stdout) self.assertIn("You need to configure ns-3 first: try ./ns3 configure", stdout)
def test_02_NoTaskLines(self): def test_02_NoTaskLines(self):
@@ -297,7 +297,7 @@ class NS3CommonSettingsTestCase(unittest.TestCase):
@return None @return None
""" """
return_code, stdout, stderr = run_ns3("--quiet") return_code, stdout, stderr = run_ns3("--quiet")
self.assertEqual(return_code, 0) self.assertEqual(return_code, 1)
self.assertIn("You need to configure ns-3 first: try ./ns3 configure", stdout) self.assertIn("You need to configure ns-3 first: try ./ns3 configure", stdout)
def test_03_CheckConfig(self): def test_03_CheckConfig(self):
@@ -307,7 +307,25 @@ class NS3CommonSettingsTestCase(unittest.TestCase):
""" """
return_code, stdout, stderr = run_ns3("--check-config") return_code, stdout, stderr = run_ns3("--check-config")
self.assertEqual(return_code, 1) self.assertEqual(return_code, 1)
self.assertIn("Project was not configured", stderr) self.assertIn("You need to configure ns-3 first: try ./ns3 configure", stdout)
def test_04_CheckProfile(self):
"""!
Test only passing --check-profile argument to ns3
@return None
"""
return_code, stdout, stderr = run_ns3("--check-profile")
self.assertEqual(return_code, 1)
self.assertIn("You need to configure ns-3 first: try ./ns3 configure", stdout)
def test_05_CheckVersion(self):
"""!
Test only passing --check-version argument to ns3
@return None
"""
return_code, stdout, stderr = run_ns3("--check-version")
self.assertEqual(return_code, 1)
self.assertIn("You need to configure ns-3 first: try ./ns3 configure", stdout)
class NS3ConfigureBuildProfileTestCase(unittest.TestCase): class NS3ConfigureBuildProfileTestCase(unittest.TestCase):
@@ -734,6 +752,33 @@ class NS3ConfigureTestCase(NS3BaseTestCase):
) )
self.assertNotEqual(return_code, 0) self.assertNotEqual(return_code, 0)
def test_10_CheckConfig(self):
"""!
Test passing --check-config argument to ns3 to get the configuration table
@return None
"""
return_code, stdout, stderr = run_ns3("--check-config")
self.assertEqual(return_code, 0)
self.assertIn("Summary of optional NS-3 features", stdout)
def test_11_CheckProfile(self):
"""!
Test passing --check-profile argument to ns3 to get the build profile
@return None
"""
return_code, stdout, stderr = run_ns3("--check-profile")
self.assertEqual(return_code, 0)
self.assertIn("Build profile: debug", stdout)
def test_12_CheckVersion(self):
"""!
Test passing --check-version argument to ns3 to get the build version
@return None
"""
return_code, stdout, stderr = run_ns3("--check-version")
self.assertEqual(return_code, 0)
self.assertIn("ns-3 version:", stdout)
class NS3BuildBaseTestCase(NS3BaseTestCase): class NS3BuildBaseTestCase(NS3BaseTestCase):
"""! """!
@@ -1047,6 +1092,32 @@ class NS3BuildBaseTestCase(NS3BaseTestCase):
# Reset flag to let it clean the build # Reset flag to let it clean the build
NS3BuildBaseTestCase.cleaned_once = False NS3BuildBaseTestCase.cleaned_once = False
def test_09_Scratches(self):
"""!
Tries to build scratch-simulator and subdir/scratch-simulator-subdir
@return None
"""
# Build.
targets = {"scratch/scratch-simulator": "scratch-simulator",
"scratch-simulator": "scratch-simulator",
"scratch/subdir/scratch-simulator-subdir": "subdir_scratch-simulator-subdir",
"subdir/scratch-simulator-subdir": "subdir_scratch-simulator-subdir",
"scratch-simulator-subdir": "subdir_scratch-simulator-subdir",
}
for (target_to_run, target_cmake) in targets.items():
# Test if build is working.
build_line = "target scratch_%s" % target_cmake
return_code, stdout, stderr = run_ns3("build %s" % target_to_run)
self.assertEqual(return_code, 0)
self.assertIn(build_line, stdout)
# Test if run is working
return_code, stdout, stderr = run_ns3("run %s" % target_to_run)
self.assertEqual(return_code, 0)
self.assertIn(build_line, stdout)
stdout = stdout.replace("scratch_%s" % target_cmake, "") # remove build lines
self.assertIn(target_to_run.split("/")[-1], stdout)
class NS3ExpectedUseTestCase(NS3BaseTestCase): class NS3ExpectedUseTestCase(NS3BaseTestCase):
"""! """!
@@ -1354,6 +1425,89 @@ class NS3ExpectedUseTestCase(NS3BaseTestCase):
self.assertEqual(fstat.st_uid, 0) # check the file was correctly chown'ed by root self.assertEqual(fstat.st_uid, 0) # check the file was correctly chown'ed by root
self.assertEqual(fstat.st_mode & stat.S_ISUID, stat.S_ISUID) # check if normal users can run as sudo self.assertEqual(fstat.st_mode & stat.S_ISUID, stat.S_ISUID) # check if normal users can run as sudo
def test_16_CommandTemplate(self):
"""!
Check if command template is working
@return None
"""
# Command templates that are empty or do not have a %s should fail
return_code0, stdout0, stderr0 = run_ns3('run sample-simulator --command-template')
self.assertEqual(return_code0, 2)
self.assertIn("argument --command-template: expected one argument", stderr0)
return_code1, stdout1, stderr1 = run_ns3('run sample-simulator --command-template=" "')
return_code2, stdout2, stderr2 = run_ns3('run sample-simulator --command-template " "')
return_code3, stdout3, stderr3 = run_ns3('run sample-simulator --command-template "echo "')
self.assertEqual((return_code1, return_code2, return_code3), (1, 1, 1))
self.assertIn("not all arguments converted during string formatting", stderr1)
self.assertEqual(stderr1, stderr2)
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"')
self.assertEqual((return_code4, return_code5), (0, 0))
self.assertIn("sample-simulator --PrintVersion", stdout4)
self.assertIn("sample-simulator --PrintVersion", stdout5)
def test_17_ForwardArgumentsToRunTargets(self):
"""!
Check if all flavors of different argument passing to
executable targets are working
@return None
"""
# 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')
self.assertEqual((return_code0, return_code1, return_code2), (0, 0, 0))
self.assertIn("sample-simulator --help", stdout0)
self.assertIn("sample-simulator --help", stdout1)
self.assertIn("sample-simulator --help", stdout2)
# Test if the same thing happens with an additional run argument (e.g. --no-build)
return_code0, stdout0, stderr0 = run_ns3('run "sample-simulator --help" --no-build')
return_code1, stdout1, stderr1 = run_ns3('run sample-simulator --command-template="%s --help" --no-build')
return_code2, stdout2, stderr2 = run_ns3('run sample-simulator --no-build -- --help')
self.assertEqual((return_code0, return_code1, return_code2), (0, 0, 0))
self.assertEqual(stdout0, stdout1)
self.assertEqual(stdout1, stdout2)
self.assertEqual(stderr0, stderr1)
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"')
self.assertEqual((return_code0, return_code1, return_code2), (0, 0, 0))
self.assertIn("sample-simulator --PrintGlobals", stdout0)
self.assertIn("sample-simulator --PrintGroups", stdout1)
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'
return_code, stdout, stderr = run_ns3(cmd)
self.assertEqual(return_code, 0)
# The order of the arguments is command template,
# arguments passed with the target itself
# and forwarded arguments after the -- separator
self.assertIn("sample-simulator --PrintGroups --PrintGlobals --PrintTypeIds", stdout)
# Check if it complains about the missing -- separator
cmd0 = 'run sample-simulator --command-template="%s " --PrintTypeIds'
cmd1 = 'run sample-simulator --PrintTypeIds'
return_code0, stdout0, stderr0 = run_ns3(cmd0)
return_code1, stdout1, stderr1 = run_ns3(cmd1)
self.assertEqual((return_code0, return_code1), (1, 1))
self.assertIn("To forward configuration or runtime options, put them after '--'", stderr0)
self.assertIn("To forward configuration or runtime options, put them after '--'", stderr1)
if __name__ == '__main__': if __name__ == '__main__':
loader = unittest.TestLoader() loader = unittest.TestLoader()