build: refactoring CMake and ns3

Includes:
- summarize ns3 commands on top-level --help
- add --quiet as a post-positional argument
- refactor verbose variable names
- aggregate ./ns3 --check-config|profile|version into ./ns3 show config|profile|version
- remove ns3 --check deprecated option
- set VERBOSE environment variable when building/running with -v/--verbose
  https://gitlab.com/nsnam/ns-3-dev/-/issues/590#note_870520212
- enable verbose Makefiles when NS3_VERBOSE is enabled
  https://gitlab.com/nsnam/ns-3-dev/-/issues/590
- introduce default build profile and refactor others
  https://gitlab.com/nsnam/ns-3-dev/-/issues/591
- use "-Og" in "CMAKE_BUILD_TYPE=Debug"/"ns3 -d debug"
- add back FindPython3 and fallback to FindPythonInterp if needed
- redirect pybindgen apiscan output to apiscan.log
- enable CMAKE_FIND_DEBUG_MODE with NS3_VERBOSE and CMake >= 3.17
- add search path logging to find_external_library
  Requires NS3_VERBOSE=ON. This is an anternative to CMAKE_FIND_DEBUG_MODE=true available in CMake >= 3.17
- remove C support
- reduce Int128 checks
- fuse Boost Units Quantity and SI header checks
- replace not found messages with skipping
This commit is contained in:
Gabriel Ferreira
2022-03-02 11:51:53 -03:00
parent f728b1f8d0
commit fbebb61a6f
13 changed files with 511 additions and 361 deletions

View File

@@ -19,7 +19,7 @@ endif()
# ############################################################################## # ##############################################################################
# Project name # # Project name #
# ############################################################################## # ##############################################################################
project(NS3 CXX C) project(NS3 CXX)
file(STRINGS VERSION NS3_VER) file(STRINGS VERSION NS3_VER)

View File

@@ -1,152 +0,0 @@
# # COPYRIGHT
#
# All contributions by Emanuele Ruffaldi Copyright (c) 2016-2019, E All rights
# reserved.
#
# All other contributions: Copyright (c) 2019, the respective contributors. All
# rights reserved.
#
# Each contributor holds copyright over their respective contributions. The
# project versioning (Git) records all such contribution source information.
#
# LICENSE
#
# The BSD 3-Clause License
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# * Neither the name of tiny-dnn nor the names of its contributors may be used
# to endorse or promote products derived from this software without specific
# prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# SOURCE:
# https://github.com/eruffaldi/cppPosit/blob/master/include/FindInt128.cmake
#
# * this module looks for 128 bit integer support. It sets up the type defs in
# util/int128_types.hpp. Simply add ${INT128_FLAGS} to the compiler flags.
include(CheckTypeSize)
include(CheckCXXSourceCompiles)
macro(CHECK_128_BIT_HASH_FUNCTION VAR_NAME DEF_NAME)
# message("Testing for presence of 128 bit unsigned integer hash function for
# ${VAR_NAME}.")
check_cxx_source_compiles(
"
#include <functional>
#include <cstdint>
int main(int argc, char** argv) {
std::hash<${VAR_NAME}>()(0);
return 0;
}"
has_hash_${VAR_NAME}
)
if(has_hash_${VAR_NAME})
# message("std::hash<${VAR_NAME}> defined.")
set(${DEF_NAME} 1)
else()
# message("std::hash<${VAR_NAME}> not defined.")
endif()
endmacro()
macro(CHECK_INT128 INT128_NAME VARIABLE DEFINE_NAME)
if(NOT INT128_FOUND)
# message("Testing for 128 bit integer support with ${INT128_NAME}.")
check_type_size("${INT128_NAME}" int128_t_${DEFINE_NAME})
if(HAVE_int128_t_${DEFINE_NAME})
if(int128_t_${DEFINE_NAME} EQUAL 16)
# message("Found: Enabling support for 128 bit integers using
# ${INT128_NAME}.")
set(INT128_FOUND 1)
check_128_bit_hash_function(${INT128_NAME} HAS_INT128_STD_HASH)
set(${VARIABLE} "${DEFINE_NAME}")
else()
# message("${INT128_NAME} has incorrect size, can't use.")
endif()
endif()
endif()
endmacro()
macro(CHECK_UINT128 UINT128_NAME VARIABLE DEFINE_NAME)
if(NOT UINT128_FOUND)
# message("Testing for 128 bit unsigned integer support with
# ${UINT128_NAME}.")
check_type_size("${UINT128_NAME}" uint128_t_${DEFINE_NAME})
if(HAVE_uint128_t_${DEFINE_NAME})
if(uint128_t_${DEFINE_NAME} EQUAL 16)
# message("Found: Enabling support for 128 bit integers using
# ${UINT128_NAME}.")
set(UINT128_FOUND 1)
check_128_bit_hash_function(${UINT128_NAME} HAS_UINT128_STD_HASH)
set(${VARIABLE} "${DEFINE_NAME}")
else()
# message("${UINT128_NAME} has incorrect size, can't use.")
endif()
endif()
endif()
endmacro()
macro(FIND_INT128_TYPES)
check_int128("long long" INT128_DEF "HAVEint128_as_long_long")
check_int128("int128_t" INT128_DEF "HAVEint128_t")
check_int128("__int128_t" INT128_DEF "HAVE__int128_t")
check_int128("__int128" INT128_DEF "HAVE__int128")
check_int128("int128" INT128_DEF "HAVEint128")
if(INT128_FOUND)
set(INT128_FLAGS "-D${INT128_DEF}")
if(HAS_INT128_STD_HASH)
set(INT128_FLAGS "${INT128_FLAGS} -DHASH_FOR_INT128_DEFINED")
endif()
endif()
check_uint128("unsigned long long" UINT128_DEF "HAVEuint128_as_u_long_long")
check_uint128("uint128_t" UINT128_DEF "HAVEuint128_t")
check_uint128("__uint128_t" UINT128_DEF "HAVE__uint128_t")
check_uint128("__uint128" UINT128_DEF "HAVE__uint128")
check_uint128("uint128" UINT128_DEF "HAVEuint128")
check_uint128("unsigned __int128_t" UINT128_DEF "HAVEunsigned__int128_t")
check_uint128("unsigned int128_t" UINT128_DEF "HAVEunsignedint128_t")
check_uint128("unsigned __int128" UINT128_DEF "HAVEunsigned__int128")
check_uint128("unsigned int128" UINT128_DEF "HAVEunsignedint128")
if(UINT128_FOUND)
set(INT128_FLAGS "${INT128_FLAGS} -D${UINT128_DEF}")
if(HAS_UINT128_STD_HASH)
set(INT128_FLAGS "${INT128_FLAGS} -DHASH_FOR_UINT128_DEFINED")
endif()
endif()
# MSVC doesn't support 128 bit soft operations, which is weird since they
# support 128 bit numbers... Clang does support, but didn't expose them
# https://reviews.llvm.org/D41813
if(${MSVC})
set(UINT128_FOUND False)
endif()
endmacro()

View File

@@ -85,7 +85,7 @@ function(write_lock)
string(APPEND lock_contents "APPNAME = 'ns'\n") string(APPEND lock_contents "APPNAME = 'ns'\n")
string(APPEND lock_contents "BUILD_PROFILE = '${build_profile}'\n") string(APPEND lock_contents "BUILD_PROFILE = '${build_profile}'\n")
string(APPEND lock_contents "VERSION = '${NS3_VER}' \n") string(APPEND lock_contents "VERSION = '${NS3_VER}' \n")
string(APPEND lock_contents "PYTHON = ['${Python_EXECUTABLE}']\n") string(APPEND lock_contents "PYTHON = ['${Python3_EXECUTABLE}']\n")
mark_as_advanced(VALGRIND) mark_as_advanced(VALGRIND)
find_program(VALGRIND valgrind) find_program(VALGRIND valgrind)

View File

@@ -279,7 +279,7 @@ function(build_lib)
set(module_api_LP64 ${bindings_output_folder}/modulegen__gcc_LP64.py) set(module_api_LP64 ${bindings_output_folder}/modulegen__gcc_LP64.py)
set(modulescan_modular_command set(modulescan_modular_command
${Python_EXECUTABLE} ${Python3_EXECUTABLE}
${PROJECT_SOURCE_DIR}/bindings/python/ns3modulescan-modular.py ${PROJECT_SOURCE_DIR}/bindings/python/ns3modulescan-modular.py
) )
@@ -305,7 +305,7 @@ function(build_lib)
if("${arch}" STREQUAL "gcc_LP64") if("${arch}" STREQUAL "gcc_LP64")
set(module_to_generate_api ${module_api_LP64}) set(module_to_generate_api ${module_api_LP64})
set(LP64toILP32 set(LP64toILP32
${Python_EXECUTABLE} ${Python3_EXECUTABLE}
${PROJECT_SOURCE_DIR}/build-support/pybindings-LP64-to-ILP32.py ${PROJECT_SOURCE_DIR}/build-support/pybindings-LP64-to-ILP32.py
${module_api_LP64} ${module_api_ILP32} ${module_api_LP64} ${module_api_ILP32}
) )
@@ -316,7 +316,8 @@ function(build_lib)
COMMAND COMMAND
${modulescan_modular_command} ${CMAKE_OUTPUT_DIRECTORY} ${BLIB_LIBNAME} ${modulescan_modular_command} ${CMAKE_OUTPUT_DIRECTORY} ${BLIB_LIBNAME}
${PROJECT_BINARY_DIR}/header_map.json ${module_to_generate_api} ${PROJECT_BINARY_DIR}/header_map.json ${module_to_generate_api}
\"${arch_flags} ${modulegen_include_dirs}\" \"${arch_flags} ${modulegen_include_dirs}\" 2>
${bindings_output_folder}/apiscan.log
COMMAND ${LP64toILP32} COMMAND ${LP64toILP32}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
DEPENDS ${lib${BLIB_LIBNAME}} DEPENDS ${lib${BLIB_LIBNAME}}
@@ -357,7 +358,7 @@ function(build_lib)
) )
set(modulegen_modular_command set(modulegen_modular_command
GCC_RTTI_ABI_COMPLETE=True NS3_ENABLED_FEATURES="${ENABLED_FEATURES}" GCC_RTTI_ABI_COMPLETE=True NS3_ENABLED_FEATURES="${ENABLED_FEATURES}"
${Python_EXECUTABLE} ${Python3_EXECUTABLE}
${PROJECT_SOURCE_DIR}/bindings/python/ns3modulegen-modular.py ${PROJECT_SOURCE_DIR}/bindings/python/ns3modulegen-modular.py
) )
execute_process( execute_process(
@@ -394,7 +395,7 @@ function(build_lib)
set(bindings-name lib${BLIB_LIBNAME}-bindings) set(bindings-name lib${BLIB_LIBNAME}-bindings)
add_library(${bindings-name} SHARED "${python_module_files}") add_library(${bindings-name} SHARED "${python_module_files}")
target_include_directories( target_include_directories(
${bindings-name} PUBLIC ${PYTHON_INCLUDE_DIRS} ${bindings_output_folder} ${bindings-name} PUBLIC ${Python3_INCLUDE_DIRS} ${bindings_output_folder}
) )
target_compile_options(${bindings-name} PRIVATE -Wno-error) target_compile_options(${bindings-name} PRIVATE -Wno-error)
@@ -410,7 +411,7 @@ function(build_lib)
${bindings-name} ${bindings-name}
PUBLIC ${LIB_AS_NEEDED_PRE} ${lib${BLIB_LIBNAME}} "${bindings_to_link}" PUBLIC ${LIB_AS_NEEDED_PRE} ${lib${BLIB_LIBNAME}} "${bindings_to_link}"
"${BLIB_LIBRARIES_TO_LINK}" ${LIB_AS_NEEDED_POST} "${BLIB_LIBRARIES_TO_LINK}" ${LIB_AS_NEEDED_POST}
PRIVATE ${Python_LIBRARIES} PRIVATE ${Python3_LIBRARIES}
) )
target_include_directories( target_include_directories(
${bindings-name} PRIVATE ${PROJECT_SOURCE_DIR}/src/core/bindings ${bindings-name} PRIVATE ${PROJECT_SOURCE_DIR}/src/core/bindings

View File

@@ -282,25 +282,41 @@ endfunction()
macro(process_options) macro(process_options)
clear_global_cached_variables() clear_global_cached_variables()
# make sure to default to debug if no build type is specified # make sure to default to RelWithDebInfo if no build type is specified
if(NOT CMAKE_BUILD_TYPE) if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Choose the type of build." FORCE) set(CMAKE_BUILD_TYPE "default" CACHE STRING "Choose the type of build."
FORCE
)
set(NS3_ASSERT ON CACHE BOOL "Enable assert on failure" FORCE)
set(NS3_LOG ON CACHE BOOL "Enable logging to be built" FORCE)
set(NS3_WARNINGS_AS_ERRORS OFF
CACHE BOOL "Treat warnings as errors. Requires NS3_WARNINGS=ON" FORCE
)
endif() endif()
# process debug switch Used in build-profile-test-suite # process debug switch Used in build-profile-test-suite
string(TOLOWER ${CMAKE_BUILD_TYPE} cmakeBuildType) string(TOLOWER ${CMAKE_BUILD_TYPE} cmakeBuildType)
set(build_profile "${cmakeBuildType}" CACHE INTERNAL "") set(build_profile "${cmakeBuildType}" CACHE INTERNAL "")
if(${cmakeBuildType} STREQUAL "debug") if(${cmakeBuildType} STREQUAL "debug")
string(REPLACE "-g" "-Og -g" CMAKE_CXX_FLAGS_DEBUG
"${CMAKE_CXX_FLAGS_DEBUG}"
)
add_definitions(-DNS3_BUILD_PROFILE_DEBUG)
elseif(${cmakeBuildType} STREQUAL "relwithdebinfo" OR ${cmakeBuildType}
STREQUAL "default"
)
set(cmakeBuildType relwithdebinfo)
set(CMAKE_CXX_FLAGS_DEFAULT ${CMAKE_CXX_FLAGS_RELWITHDEBINFO})
add_definitions(-DNS3_BUILD_PROFILE_DEBUG) add_definitions(-DNS3_BUILD_PROFILE_DEBUG)
elseif(${cmakeBuildType} STREQUAL "relwithdebinfo")
add_definitions(-DNS3_BUILD_PROFILE_RELEASE)
elseif(${cmakeBuildType} STREQUAL "release") elseif(${cmakeBuildType} STREQUAL "release")
add_definitions(-DNS3_BUILD_PROFILE_OPTIMIZED)
if(${NS3_NATIVE_OPTIMIZATIONS}) if(${NS3_NATIVE_OPTIMIZATIONS})
add_definitions(-DNS3_BUILD_PROFILE_OPTIMIZED)
set(build_profile "optimized" CACHE INTERNAL "") set(build_profile "optimized" CACHE INTERNAL "")
else()
add_definitions(-DNS3_BUILD_PROFILE_RELEASE)
endif() endif()
else() else()
add_definitions(-DNS3_BUILD_PROFILE_OPTIMIZED) add_definitions(-DNS3_BUILD_PROFILE_RELEASE)
endif() endif()
# Enable examples if activated via command line (NS3_EXAMPLES) or ns3rc config # Enable examples if activated via command line (NS3_EXAMPLES) or ns3rc config
@@ -656,17 +672,36 @@ macro(process_options)
endif() endif()
endif() endif()
set(Python3_LIBRARIES)
set(Python3_EXECUTABLE)
set(Python3_FOUND FALSE)
set(Python3_INCLUDE_DIRS)
if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.12.0")
find_package(Python3 COMPONENTS Interpreter Development)
else()
# cmake-format: off # cmake-format: off
set(Python_ADDITIONAL_VERSIONS 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 3.10 3.11) set(Python_ADDITIONAL_VERSIONS 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9)
# cmake-format: on # cmake-format: on
find_package(PythonInterp) find_package(PythonInterp)
set(Python_EXECUTABLE)
set(Python_FOUND FALSE)
if(${PythonInterp_FOUND})
set(Python_EXECUTABLE ${PYTHON_EXECUTABLE})
find_package(PythonLibs) find_package(PythonLibs)
if(${PythonLibs_FOUND})
set(Python_FOUND TRUE) # 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()
# Check if both Python interpreter and development libraries were found
if(${Python3_Interpreter_FOUND})
if(${Python3_Development_FOUND})
set(Python3_FOUND TRUE)
else() else()
message(STATUS "Python: development libraries were not found") message(STATUS "Python: development libraries were not found")
endif() endif()
@@ -679,7 +714,7 @@ macro(process_options)
set(ENABLE_PYTHON_BINDINGS OFF) set(ENABLE_PYTHON_BINDINGS OFF)
if(${NS3_PYTHON_BINDINGS}) if(${NS3_PYTHON_BINDINGS})
if(NOT ${Python_FOUND}) if(NOT ${Python3_FOUND})
message( message(
STATUS STATUS
"Bindings: python bindings require Python, but it could not be found" "Bindings: python bindings require Python, but it could not be found"
@@ -704,14 +739,16 @@ macro(process_options)
set(ENABLE_SCAN_PYTHON_BINDINGS OFF) set(ENABLE_SCAN_PYTHON_BINDINGS OFF)
if(${NS3_SCAN_PYTHON_BINDINGS}) if(${NS3_SCAN_PYTHON_BINDINGS})
if(NOT ${Python_FOUND}) if(NOT ${Python3_FOUND})
message( message(
STATUS STATUS
"Bindings: scanning python bindings require Python, but it could not be found" "Bindings: scanning python bindings require Python, but it could not be found"
) )
else() else()
# Check if pybindgen, pygccxml and cxxfilt are installed # Check if pybindgen, pygccxml and cxxfilt are installed
check_python_packages("pybindgen;pygccxml;cxxfilt" missing_packages) check_python_packages(
"pybindgen;pygccxml;cxxfilt;castxml" missing_packages
)
if(missing_packages) if(missing_packages)
message( message(
STATUS STATUS
@@ -728,7 +765,7 @@ macro(process_options)
set(ENABLE_VISUALIZER FALSE) set(ENABLE_VISUALIZER FALSE)
if(${NS3_VISUALIZER}) if(${NS3_VISUALIZER})
if((NOT ${ENABLE_PYTHON_BINDINGS}) OR (NOT ${Python_FOUND})) if((NOT ${ENABLE_PYTHON_BINDINGS}) OR (NOT ${Python3_FOUND}))
message(STATUS "Visualizer requires Python bindings") message(STATUS "Visualizer requires Python bindings")
else() else()
set(ENABLE_VISUALIZER TRUE) set(ENABLE_VISUALIZER TRUE)
@@ -750,7 +787,7 @@ macro(process_options)
# produce code coverage output # produce code coverage output
add_custom_target( add_custom_target(
run_test_py run_test_py
COMMAND ${Python_EXECUTABLE} test.py --no-build COMMAND ${Python3_EXECUTABLE} test.py --no-build
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
DEPENDS all-test-targets DEPENDS all-test-targets
) )
@@ -779,8 +816,12 @@ macro(process_options)
if(${NS3_VERBOSE}) if(${NS3_VERBOSE})
set_property(GLOBAL PROPERTY TARGET_MESSAGES TRUE) set_property(GLOBAL PROPERTY TARGET_MESSAGES TRUE)
set(CMAKE_FIND_DEBUG_MODE TRUE)
set(CMAKE_VERBOSE_MAKEFILE TRUE CACHE INTERNAL "")
else() else()
set_property(GLOBAL PROPERTY TARGET_MESSAGES OFF) set_property(GLOBAL PROPERTY TARGET_MESSAGES OFF)
unset(CMAKE_FIND_DEBUG_MODE)
unset(CMAKE_VERBOSE_MAKEFILE CACHE)
endif() endif()
mark_as_advanced(Boost_INCLUDE_DIR) mark_as_advanced(Boost_INCLUDE_DIR)
@@ -860,7 +901,7 @@ macro(process_options)
add_custom_target( add_custom_target(
run-introspected-command-line run-introspected-command-line
COMMAND ${CMAKE_COMMAND} -E env NS_COMMANDLINE_INTROSPECTION=.. COMMAND ${CMAKE_COMMAND} -E env NS_COMMANDLINE_INTROSPECTION=..
${Python_EXECUTABLE} ./test.py --no-build --constrain=example ${Python3_EXECUTABLE} ./test.py --no-build --constrain=example
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
DEPENDS all-test-targets # all-test-targets only exists if ENABLE_TESTS is DEPENDS all-test-targets # all-test-targets only exists if ENABLE_TESTS is
# set to ON # set to ON
@@ -957,12 +998,34 @@ macro(process_options)
endif() endif()
# end of checking for documentation dependencies and creating targets # end of checking for documentation dependencies and creating targets
# Adding this module manually is required by CMake 3.10
include(CheckCXXSourceCompiles)
# Process core-config If INT128 is not found, fallback to CAIRO # Process core-config If INT128 is not found, fallback to CAIRO
if(${NS3_INT64X64} MATCHES "INT128") if(${NS3_INT64X64} MATCHES "INT128")
include(build-support/3rd-party/FindInt128.cmake) check_cxx_source_compiles(
find_int128_types() "#include <stdint.h>
if(UINT128_FOUND) int main(int argc, char **argv)
set(HAVE___UINT128_T TRUE) {
(void)argc; (void)argv;
if ((uint128_t *) 0) return 0;
if (sizeof (uint128_t)) return 0;
return 1;
}"
HAVE_UINT128_T
)
check_cxx_source_compiles(
"#include <stdint.h>
int main(int argc, char **argv)
{
(void)argc; (void)argv;
if ((__uint128_t *) 0) return 0;
if (sizeof (__uint128_t)) return 0;
return 1;
}"
HAVE___UINT128_T
)
if(HAVE_UINT128_T OR HAVE___UINT128_T)
set(INT64X64_USE_128 TRUE) set(INT64X64_USE_128 TRUE)
else() else()
message(STATUS "Int128 was not found. Falling back to Cairo.") message(STATUS "Int128 was not found. Falling back to Cairo.")
@@ -994,7 +1057,8 @@ macro(process_options)
set(INT64X64_USE_CAIRO TRUE) set(INT64X64_USE_CAIRO TRUE)
endif() endif()
include(CheckIncludeFileCXX) include(CheckIncludeFileCXX) # Used to check a single header at a time
include(CheckIncludeFiles) # Used to check multiple headers at once
include(CheckFunctionExists) include(CheckFunctionExists)
# Check for required headers and functions, set flags if they're found or warn # Check for required headers and functions, set flags if they're found or warn
@@ -1231,10 +1295,7 @@ endfunction()
add_custom_target(copy_all_headers) add_custom_target(copy_all_headers)
function(copy_headers_before_building_lib libname outputdir headers visibility) function(copy_headers_before_building_lib libname outputdir headers visibility)
foreach(header ${headers}) foreach(header ${headers})
configure_file( configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${header} ${outputdir}/ COPYONLY)
${CMAKE_CURRENT_SOURCE_DIR}/${header} ${outputdir}/${header_name}
COPYONLY
)
endforeach() endforeach()
endfunction(copy_headers_before_building_lib) endfunction(copy_headers_before_building_lib)
@@ -1550,6 +1611,56 @@ function(parse_ns3rc enabled_modules examples_enabled tests_enabled)
endif() endif()
endfunction(parse_ns3rc) endfunction(parse_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) function(find_external_library)
# Parse arguments # Parse arguments
set(options QUIET) set(options QUIET)
@@ -1575,6 +1686,18 @@ function(find_external_library)
set(library_dirs) set(library_dirs)
set(libraries) set(libraries)
# Paths and suffixes where libraries will be searched on
set(library_search_paths
${search_paths}
${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
)
set(suffixes /build /lib /build/lib / /bin ${path_suffixes})
# For each of the library names in LIBRARY_NAMES or LIBRARY_NAME # For each of the library names in LIBRARY_NAMES or LIBRARY_NAME
foreach(library ${library_names}) foreach(library ${library_names})
# We mark this value is advanced not to pollute the configuration with # We mark this value is advanced not to pollute the configuration with
@@ -1585,17 +1708,9 @@ function(find_external_library)
# ${name}_library_internal_${library} # ${name}_library_internal_${library}
find_library( find_library(
${name}_library_internal_${library} ${library} ${name}_library_internal_${library} ${library}
HINTS ${search_paths} HINTS ${library_search_paths} PATH_SUFFIXES ${suffixes}
${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
PATH_SUFFIXES /build /lib /build/lib / /bin ${path_suffixes}
) )
# cmake-format: off
# Note: the PATH_SUFFIXES above apply to *ALL* PATHS and HINTS Which # Note: the PATH_SUFFIXES above apply to *ALL* PATHS and HINTS Which
# translates to CMake searching on standard library directories # translates to CMake searching on standard library directories
# CMAKE_SYSTEM_PREFIX_PATH, user-settable CMAKE_PREFIX_PATH or # CMAKE_SYSTEM_PREFIX_PATH, user-settable CMAKE_PREFIX_PATH or
@@ -1607,21 +1722,45 @@ function(find_external_library)
# Searched directories without suffixes # Searched directories without suffixes
# #
# ${CMAKE_SYSTEM_PREFIX_PATH}[0] = /usr/local/ # ${CMAKE_SYSTEM_PREFIX_PATH}[0] = /usr/local/
# ${CMAKE_SYSTEM_PREFIX_PATH}[1] = /usr ${CMAKE_SYSTEM_PREFIX_PATH}[2] = / # ${CMAKE_SYSTEM_PREFIX_PATH}[1] = /usr
# ${CMAKE_SYSTEM_PREFIX_PATH}[3] = /usr/local ${CMAKE_SYSTEM_PREFIX_PATH}[4] # ${CMAKE_SYSTEM_PREFIX_PATH}[2] = /
# = /usr/X11R6 ${CMAKE_SYSTEM_PREFIX_PATH}[5] = /usr/pkg # ...
# ${CMAKE_SYSTEM_PREFIX_PATH}[6] = /opt ${search_paths}[0] ... # ${CMAKE_SYSTEM_PREFIX_PATH}[6] = /opt
# ${search_paths}[n] ${CMAKE_OUTPUT_DIRECTORY} ${CMAKE_INSTALL_PREFIX} # ${LD_LIBRARY_PATH}[0]
# ${LD_LIBRARY_PATH}[0] ... ${LD_LIBRARY_PATH}[m] ${PATH}[0] ... ${PATH}[m] # ...
# ${LD_LIBRARY_PATH}[m]
# ${PATH}[0]
# ...
# ${PATH}[m]
# #
# Searched directories with suffixes include all of the directories above # Searched directories with suffixes include all of the directories above
# plus all suffixes PATH_SUFFIXES /build /lib /build/lib / /bin # plus all suffixes
# ${path_suffixes} # PATH_SUFFIXES /build /lib /build/lib / /bin # ${path_suffixes}
# #
# /usr/local/build /usr/local/lib /usr/local/build/lib /usr/local/bin # /usr/local/build
# /usr/local/${path_suffixes}[0] ... /usr/local/${path_suffixes}[k] # /usr/local/lib
# /usr/local/build/lib
# /usr/local/bin
# ...
# #
# /usr/build /usr/lib /usr/build/lib ... ${PATH}[m]/${path_suffixes}[k] # 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 # After searching the library, the internal variable should have either the
# absolute path to the library or the name of the variable appended with # absolute path to the library or the name of the variable appended with
@@ -1652,22 +1791,26 @@ function(find_external_library)
list(APPEND parent_dirs ${parent_libdir} ${parent_parent_libdir}) list(APPEND parent_dirs ${parent_libdir} ${parent_parent_libdir})
endforeach() endforeach()
# If we already found a library somewhere, limit the search paths for the
# header
if(parent_dirs)
set(header_search_paths ${parent_dirs})
set(header_skip_system_prefix NO_CMAKE_SYSTEM_PATH)
else()
set(header_search_paths
${search_paths} ${CMAKE_OUTPUT_DIRECTORY} # Search for headers in
# ns-3-dev/build
${CMAKE_INSTALL_PREFIX} # Search for headers in the install
)
endif()
set(not_found_headers) set(not_found_headers)
set(include_dirs) set(include_dirs)
foreach(header ${header_names}) foreach(header ${header_names})
# The same way with libraries, we mark the internal variable as advanced not # The same way with libraries, we mark the internal variable as advanced not
# to pollute ccmake configuration with variables used internally # to pollute ccmake configuration with variables used internally
mark_as_advanced(${name}_header_internal_${header}) mark_as_advanced(${name}_header_internal_${header})
set(suffixes
# Here we search for the header file named ${header} and store the result in
# ${name}_header_internal_${header}
find_file(
${name}_header_internal_${header} ${header}
HINTS ${search_paths} ${parent_dirs}
${CMAKE_OUTPUT_DIRECTORY} # Search for headers in ns-3-dev/build
${CMAKE_INSTALL_PREFIX} # Search for headers in the install
# directory (e.g. /usr/)
PATH_SUFFIXES
/build /build
/include /include
/build/include /build/include
@@ -1677,16 +1820,48 @@ function(find_external_library)
/ /
${path_suffixes} ${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 # The same way we did with libraries, here we search on
# CMAKE_SYSTEM_PREFIX_PATH, along with user-settable ${search_paths}, the # CMAKE_SYSTEM_PREFIX_PATH, along with user-settable ${search_paths}, the
# parent directories from the libraries, CMAKE_OUTPUT_DIRECTORY and # parent directories from the libraries, CMAKE_OUTPUT_DIRECTORY and
# CMAKE_INSTALL_PREFIX # CMAKE_INSTALL_PREFIX
# #
# And again, for each of them, for every suffix listed /usr/local/build # And again, for each of them, for every suffix listed /usr/local/build
# /usr/local/include /usr/local/build/include # /usr/local/include
# /usr/local/build/include/${name} /usr/local/include/${name} # /usr/local/build/include
# /usr/local/${name} /usr/local/ /usr/local/${path_suffixes}[0] ... # /usr/local/build/include/${name}
# /usr/local/${path_suffixes}[k] ... # /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 the header file was not found, append to the not-found list
if("${${name}_header_internal_${header}}" STREQUAL if("${${name}_header_internal_${header}}" STREQUAL
@@ -1766,7 +1941,7 @@ function(check_python_packages packages missing_packages)
set(missing) set(missing)
foreach(package ${packages}) foreach(package ${packages})
execute_process( execute_process(
COMMAND ${Python_EXECUTABLE} -c "import ${package}" COMMAND ${Python3_EXECUTABLE} -c "import ${package}"
RESULT_VARIABLE return_code OUTPUT_QUIET ERROR_QUIET RESULT_VARIABLE return_code OUTPUT_QUIET ERROR_QUIET
) )
if(NOT (${return_code} EQUAL 0)) if(NOT (${return_code} EQUAL 0))

View File

@@ -720,6 +720,15 @@ Here is how it works:
set(not_found_libraries) set(not_found_libraries)
set(library_dirs) set(library_dirs)
set(libraries) set(libraries)
# Paths and suffixes where libraries will be searched on
set(library_search_paths
${search_paths}
${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
)
set(suffixes /build /lib /build/lib / /bin ${path_suffixes})
# For each of the library names in LIBRARY_NAMES or LIBRARY_NAME # For each of the library names in LIBRARY_NAMES or LIBRARY_NAME
foreach(library ${library_names}) foreach(library ${library_names})
@@ -731,17 +740,10 @@ Here is how it works:
# ${name}_library_internal_${library} # ${name}_library_internal_${library}
find_library( find_library(
${name}_library_internal_${library} ${library} ${name}_library_internal_${library} ${library}
HINTS ${search_paths} HINTS ${library_search_paths}
${CMAKE_OUTPUT_DIRECTORY} # Search for libraries in ns-3-dev/build PATH_SUFFIXES ${suffixes}
${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
PATH_SUFFIXES /build /lib /build/lib / /bin ${path_suffixes}
) )
# cmake-format: off
# Note: the PATH_SUFFIXES above apply to *ALL* PATHS and HINTS Which # Note: the PATH_SUFFIXES above apply to *ALL* PATHS and HINTS Which
# translates to CMake searching on standard library directories # translates to CMake searching on standard library directories
# CMAKE_SYSTEM_PREFIX_PATH, user-settable CMAKE_PREFIX_PATH or # CMAKE_SYSTEM_PREFIX_PATH, user-settable CMAKE_PREFIX_PATH or
@@ -753,21 +755,38 @@ Here is how it works:
# Searched directories without suffixes # Searched directories without suffixes
# #
# ${CMAKE_SYSTEM_PREFIX_PATH}[0] = /usr/local/ # ${CMAKE_SYSTEM_PREFIX_PATH}[0] = /usr/local/
# ${CMAKE_SYSTEM_PREFIX_PATH}[1] = /usr ${CMAKE_SYSTEM_PREFIX_PATH}[2] = / # ${CMAKE_SYSTEM_PREFIX_PATH}[1] = /usr
# ${CMAKE_SYSTEM_PREFIX_PATH}[3] = /usr/local ${CMAKE_SYSTEM_PREFIX_PATH}[4] # ${CMAKE_SYSTEM_PREFIX_PATH}[2] = /
# = /usr/X11R6 ${CMAKE_SYSTEM_PREFIX_PATH}[5] = /usr/pkg # ...
# ${CMAKE_SYSTEM_PREFIX_PATH}[6] = /opt ${search_paths}[0] ... # ${CMAKE_SYSTEM_PREFIX_PATH}[6] = /opt
# ${search_paths}[n] ${CMAKE_OUTPUT_DIRECTORY} ${CMAKE_INSTALL_PREFIX} # ${LD_LIBRARY_PATH}[0]
# ${LD_LIBRARY_PATH}[0] ... ${LD_LIBRARY_PATH}[m] ${PATH}[0] ... ${PATH}[m] # ...
# ${LD_LIBRARY_PATH}[m]
# ...
# #
# Searched directories with suffixes include all of the directories above # Searched directories with suffixes include all of the directories above
# plus all suffixes PATH_SUFFIXES /build /lib /build/lib / /bin # plus all suffixes
# ${path_suffixes} # PATH_SUFFIXES /build /lib /build/lib / /bin # ${path_suffixes}
# #
# /usr/local/build /usr/local/lib /usr/local/build/lib /usr/local/bin # /usr/local/build
# /usr/local/${path_suffixes}[0] ... /usr/local/${path_suffixes}[k] # /usr/local/lib
# /usr/local/build/lib
# /usr/local/bin
# ...
# #
# /usr/build /usr/lib /usr/build/lib ... ${PATH}[m]/${path_suffixes}[k] # 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})
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 # After searching the library, the internal variable should have either the
# absolute path to the library or the name of the variable appended with # absolute path to the library or the name of the variable appended with
@@ -798,22 +817,25 @@ Here is how it works:
list(APPEND parent_dirs ${parent_libdir} ${parent_parent_libdir}) list(APPEND parent_dirs ${parent_libdir} ${parent_parent_libdir})
endforeach() endforeach()
# If we already found a library somewhere, limit the search paths for the header
if(parent_dirs)
set(header_search_paths ${parent_dirs})
set(header_skip_system_prefix NO_CMAKE_SYSTEM_PATH)
else()
set(header_search_paths
${search_paths}
${CMAKE_OUTPUT_DIRECTORY} # Search for headers in ns-3-dev/build
${CMAKE_INSTALL_PREFIX} # Search for headers in the install
)
endif()
set(not_found_headers) set(not_found_headers)
set(include_dirs) set(include_dirs)
foreach(header ${header_names}) foreach(header ${header_names})
# The same way with libraries, we mark the internal variable as advanced not # The same way with libraries, we mark the internal variable as advanced not
# to pollute ccmake configuration with variables used internally # to pollute ccmake configuration with variables used internally
mark_as_advanced(${name}_header_internal_${header}) mark_as_advanced(${name}_header_internal_${header})
set(suffixes
# Here we search for the header file named ${header} and store the result in
# ${name}_header_internal_${header}
find_file(
${name}_header_internal_${header} ${header}
HINTS ${search_paths} ${parent_dirs}
${CMAKE_OUTPUT_DIRECTORY} # Search for headers in ns-3-dev/build
${CMAKE_INSTALL_PREFIX} # Search for headers in the install
# directory (e.g. /usr/)
PATH_SUFFIXES
/build /build
/include /include
/build/include /build/include
@@ -823,16 +845,43 @@ Here is how it works:
/ /
${path_suffixes} ${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 # The same way we did with libraries, here we search on
# CMAKE_SYSTEM_PREFIX_PATH, along with user-settable ${search_paths}, the # CMAKE_SYSTEM_PREFIX_PATH, along with user-settable ${search_paths}, the
# parent directories from the libraries, CMAKE_OUTPUT_DIRECTORY and # parent directories from the libraries, CMAKE_OUTPUT_DIRECTORY and
# CMAKE_INSTALL_PREFIX # CMAKE_INSTALL_PREFIX
# #
# And again, for each of them, for every suffix listed /usr/local/build # And again, for each of them, for every suffix listed /usr/local/build
# /usr/local/include /usr/local/build/include # /usr/local/include
# /usr/local/build/include/${name} /usr/local/include/${name} # /usr/local/build/include
# /usr/local/${name} /usr/local/ /usr/local/${path_suffixes}[0] ... # /usr/local/build/include/${name}
# /usr/local/${path_suffixes}[k] ... # /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})
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 the header file was not found, append to the not-found list
if("${${name}_header_internal_${header}}" STREQUAL if("${${name}_header_internal_${header}}" STREQUAL
@@ -879,6 +928,20 @@ Here is how it works:
endif() endif()
endfunction() endfunction()
Debugging why a header or a library cannot be found is fairly tricky.
For ``find_external_library`` users, enabling the ``NS3_VERBOSE`` switch
will enable the logging of search path directories for both headers and
libraries.
.. _CMAKE_FIND_DEBUG_MODE: https://cmake.org/cmake/help/latest/variable/CMAKE_FIND_DEBUG_MODE.html
Note: The logging provided by find_external_library is an alternative to
CMake's own ``CMAKE_FIND_DEBUG_MODE=true`` introduced in CMake 3.17,
which gets used by *ALL* ``find_file``, ``find_library``, ``find_header``,
``find_package`` and ``find_path`` calls throughout CMake and its modules.
If you are using a recent version of CMake, it is recommended to use
`CMAKE_FIND_DEBUG_MODE`_ instead.
A commented version of the Openflow module ``CMakeLists.txt`` has an A commented version of the Openflow module ``CMakeLists.txt`` has an
example of ``find_external_library`` usage. example of ``find_external_library`` usage.

152
ns3
View File

@@ -14,20 +14,20 @@ out_dir = os.sep.join([ns3_path, "build"])
lock_file = os.sep.join([ns3_path, ".lock-ns3_%s_build" % sys.platform]) lock_file = os.sep.join([ns3_path, ".lock-ns3_%s_build" % sys.platform])
print_buffer = "" print_buffer = ""
verbose = True run_verbose = True
# Prints everything in the print_buffer on exit # Prints everything in the print_buffer on exit
def exit_handler(dry_run): def exit_handler(dry_run):
global print_buffer, verbose global print_buffer, run_verbose
# We should not print anything in run except if dry_run or verbose # We should not print anything in run except if dry_run or run_verbose
if not dry_run and not verbose: if not dry_run and not run_verbose:
return return
if print_buffer == "": if print_buffer == "":
return return
if dry_run: if dry_run:
print("The following commands would be executed:") print("The following commands would be executed:")
elif verbose: elif run_verbose:
print("Finished executing the following commands:") print("Finished executing the following commands:")
print(print_buffer[1:]) print(print_buffer[1:])
@@ -56,7 +56,7 @@ def on_off_condition(args, cmake_flag, option_name):
def parse_args(argv): def parse_args(argv):
parser = argparse.ArgumentParser(description="ns-3 wrapper for the CMake build system") parser = argparse.ArgumentParser(description="ns-3 wrapper for the CMake build system", add_help=False)
sub_parser = parser.add_subparsers() sub_parser = parser.add_subparsers()
parser_build = sub_parser.add_parser('build', parser_build = sub_parser.add_parser('build',
@@ -68,6 +68,12 @@ def parse_args(argv):
parser_build.add_argument('--dry-run', parser_build.add_argument('--dry-run',
help="Do not execute the commands", help="Do not execute the commands",
action="store_true", default=None, dest="build_dry_run") action="store_true", default=None, dest="build_dry_run")
parser_build.add_argument('-v', '--verbose',
help="Print verbose build commands",
action="store_true", default=None, dest="build_verbose")
parser_build.add_argument('--quiet',
help="Don't print task lines, i.e. messages saying which tasks are being executed.",
action="store_true", default=None, dest="build_quiet")
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')
@@ -76,7 +82,7 @@ def parse_args(argv):
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',
choices=["debug", "release", "optimized"], choices=["debug", "default", "release", "optimized"],
action="store", type=str, default=None) action="store", type=str, default=None)
parser_configure.add_argument('-G', parser_configure.add_argument('-G',
@@ -162,6 +168,9 @@ def parse_args(argv):
parser_configure.add_argument('--dry-run', parser_configure.add_argument('--dry-run',
help="Do not execute the commands", help="Do not execute the commands",
action="store_true", default=None, dest="configure_dry_run") action="store_true", default=None, dest="configure_dry_run")
parser_configure.add_argument('--quiet',
help="Don't print task lines, i.e. messages saying which tasks are being executed.",
action="store_true", default=None, dest="configure_quiet")
parser_clean = sub_parser.add_parser('clean', help='Removes files created by ns3') 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.add_argument('clean', action="store_true", default=False)
@@ -214,6 +223,9 @@ def parse_args(argv):
help='Print which commands were executed', help='Print which commands were executed',
dest='run_verbose', action='store_true', dest='run_verbose', action='store_true',
default=False) default=False)
parser_run.add_argument('--quiet',
help="Don't print task lines, i.e. messages saying which tasks are being executed.",
action="store_true", default=None, dest="run_quiet")
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')
@@ -228,6 +240,9 @@ def parse_args(argv):
choices=["manual", "models", "tutorial", "contributing", choices=["manual", "models", "tutorial", "contributing",
"sphinx", "doxygen-no-build", "doxygen", "all"], "sphinx", "doxygen-no-build", "doxygen", "all"],
action="store", type=str, default=None) action="store", type=str, default=None)
parser_docs.add_argument('--quiet',
help="Don't print task lines, i.e. messages saying which tasks are being executed.",
action="store_true", default=None, dest="docs_quiet")
parser.add_argument('-j', '--jobs', parser.add_argument('-j', '--jobs',
help='Set number of parallel jobs', help='Set number of parallel jobs',
@@ -235,23 +250,26 @@ def parse_args(argv):
parser.add_argument('--dry-run', parser.add_argument('--dry-run',
help="Do not execute the commands", help="Do not execute the commands",
action="store_true", default=None, dest="dry_run") action="store_true", default=None, dest="dry_run")
parser.add_argument('--check-config',
help='Print the current configuration.',
action="store_true", default=None)
parser.add_argument('--quiet', parser.add_argument('--quiet',
help="Don't print task lines, i.e. messages saying which tasks are being executed.", help="Don't print task lines, i.e. messages saying which tasks are being executed.",
action="store_true", default=None) action="store_true", default=None, dest="quiet")
parser.add_argument('--help',
help="Print a summary of available commands",
action="store_true", default=None, dest="help")
parser.add_argument('--check', parser_show = sub_parser.add_parser('show',
help='DEPRECATED (run ./test.py)', help='Try "./ns3 show --help" for more runtime options')
action='store_true', default=None) parser_show.add_argument('show',
parser.add_argument('--check-profile', help='Print build profile type, ns-3 version or current configuration',
help='Print out current build profile', choices=["profile", "version", "config"],
action='store_true', default=None) action="store", type=str, default=None)
parser.add_argument('--check-version', parser_show.add_argument('--dry-run',
help='Print the current build version', help="Do not execute the commands",
action='store_true', default=None) action="store_true", default=None, dest="show_dry_run")
parser_show.add_argument('--quiet',
help="Don't print task lines, i.e. messages saying which tasks are being executed.",
action="store_true", default=None, dest="show_quiet")
# parser.add_argument('--docset', # parser.add_argument('--docset',
# help=( # help=(
@@ -263,13 +281,37 @@ def parse_args(argv):
# Parse known arguments and separate from unknown arguments # Parse known arguments and separate from unknown arguments
args, unknown_args = parser.parse_known_args(argv) args, unknown_args = parser.parse_known_args(argv)
# Merge dry_runs if args.help:
dry_run_args = [(args.__getattribute__(name) if name in args else None) for name in print(parser.description)
["build_dry_run", "clean_dry_run", "configure_dry_run", "dry_run", "run_dry_run"]] print("")
args.dry_run = dry_run_args.count(True) > 0 print(parser.format_usage())
# retrieve subparsers from parser
subparsers_actions = [
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:
# get all subparsers and print help
for choice, subparser in subparsers_action.choices.items():
#print("Subparser '{}'".format(choice))
subcommand = subparser.format_usage()[:-1].replace("usage: ", " or: ")
if len(subcommand) > 1:
print(subcommand)
print(parser.format_help().replace(parser.description, "").replace(parser.format_usage(), ""))
exit(0)
# Merge attributes
attributes_to_merge = ["dry_run", "verbose", "quiet"]
filtered_attributes = list(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))
setattr(args, attribute, merging_attributes.count(True) > 0)
# If some positional options are not in args, set them to false. # If some positional options are not in args, set them to false.
for option in ["clean", "configure", "docs", "install", "run", "shell", "uninstall"]: for option in ["clean", "configure", "docs", "install", "run", "shell", "uninstall", "show"]:
if option not in args: if option not in args:
setattr(args, option, False) setattr(args, option, False)
@@ -445,7 +487,7 @@ def configure_cmake(cmake, args, current_cmake_cache_folder, current_cmake_gener
# Set default build type to default if a previous cache doesn't exist # Set default build type to default if a previous cache doesn't exist
if args.build_profile is None: if args.build_profile is None:
args.build_profile = "debug" args.build_profile = "default"
# Set generator if a previous cache doesn't exist # Set generator if a previous cache doesn't exist
if args.G is None: if args.G is None:
@@ -458,13 +500,15 @@ def configure_cmake(cmake, args, current_cmake_cache_folder, current_cmake_gener
# Build type # Build type
if args.build_profile is not None: if args.build_profile is not None:
args.build_profile = args.build_profile.lower() args.build_profile = args.build_profile.lower()
if args.build_profile not in ["debug", "release", "optimized"]: if args.build_profile not in ["debug", "default", "release", "optimized"]:
raise Exception("Unknown build type") raise Exception("Unknown build type")
else: else:
if args.build_profile == "debug": if args.build_profile == "debug":
cmake_args.append("-DCMAKE_BUILD_TYPE=debug") cmake_args.extend("-DCMAKE_BUILD_TYPE=debug -DNS3_ASSERT=ON -DNS3_LOG=ON -DNS3_WARNINGS_AS_ERRORS=ON".split())
elif args.build_profile == "default":
cmake_args.extend("-DCMAKE_BUILD_TYPE=default -DNS3_ASSERT=ON -DNS3_LOG=ON -DNS3_WARNINGS_AS_ERRORS=OFF".split())
else: else:
cmake_args.append("-DCMAKE_BUILD_TYPE=release") cmake_args.extend("-DCMAKE_BUILD_TYPE=release -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"), options = (("ASSERT", "asserts"),
@@ -652,7 +696,7 @@ def cmake_check_version():
return cmake, version return cmake, version
def cmake_build(current_cmake_cache_folder, output, jobs, target=None, dry_run=False): def cmake_build(current_cmake_cache_folder, output, jobs, target=None, dry_run=False, build_verbose=False):
_, version = cmake_check_version() _, version = cmake_check_version()
# Older CMake versions don't accept the number of jobs directly # Older CMake versions don't accept the number of jobs directly
@@ -673,6 +717,11 @@ def cmake_build(current_cmake_cache_folder, output, jobs, target=None, dry_run=F
else: else:
kwargs = {"stdout": output} kwargs = {"stdout": output}
proc_env = os.environ.copy()
if build_verbose:
proc_env.update({"VERBOSE": "1"})
kwargs["env"] = proc_env
ret = subprocess.run(cmake_build_command.split(), ret = subprocess.run(cmake_build_command.split(),
cwd=current_cmake_cache_folder, cwd=current_cmake_cache_folder,
**kwargs **kwargs
@@ -815,12 +864,13 @@ def build_step(args,
ns3_version, ns3_version,
build_profile, build_profile,
output): output):
# There are two scenarios where we build everything: ./ns3 build and ./ns3 --check # There is one scenarios where we build everything: ./ns3 build
if args.check or ("build" in args and len(args.build) == 0): if "build" in args and len(args.build) == 0:
cmake_build(current_cmake_cache_folder, cmake_build(current_cmake_cache_folder,
jobs=args.jobs, jobs=args.jobs,
output=output, output=output,
dry_run=args.dry_run dry_run=args.dry_run,
build_verbose=args.verbose
) )
# If we are building specific targets, we build them one by one # If we are building specific targets, we build them one by one
@@ -860,7 +910,8 @@ def build_step(args,
jobs=args.jobs, jobs=args.jobs,
target=target, target=target,
output=output, output=output,
dry_run=args.dry_run) dry_run=args.dry_run,
build_verbose=args.verbose)
# The remaining case is when we want to build something to run # The remaining case is when we want to build something to run
if build_and_run: if build_and_run:
@@ -868,7 +919,8 @@ def build_step(args,
jobs=args.jobs, jobs=args.jobs,
target=get_target_to_build(target_to_run, ns3_version, build_profile), target=get_target_to_build(target_to_run, ns3_version, build_profile),
output=output, output=output,
dry_run=args.dry_run dry_run=args.dry_run,
build_verbose=args.verbose
) )
@@ -894,11 +946,7 @@ def run_step(args, target_to_run, target_args):
use_shell = False use_shell = False
target_args += args.program_args target_args += args.program_args
# running test.py/check? if args.shell:
if args.check:
target_to_run = os.sep.join([ns3_path, "test.py"])
target_args = ["--no-build", "--jobs=%d" % args.jobs]
elif args.shell:
target_to_run = "bash" target_to_run = "bash"
use_shell = True use_shell = True
else: else:
@@ -941,7 +989,7 @@ def run_step(args, target_to_run, target_args):
program_arguments = [*debugging_software, target_to_run, *target_args] program_arguments = [*debugging_software, target_to_run, *target_args]
if verbose or args.dry_run: if run_verbose or args.dry_run:
exported_variables = "export " exported_variables = "export "
for (variable, value) in custom_env.items(): for (variable, value) in custom_env.items():
if variable == "PATH": if variable == "PATH":
@@ -1045,7 +1093,7 @@ def refuse_run_as_root():
def main(): def main():
global out_dir, verbose global out_dir, run_verbose
# Refuse to run with sudo # Refuse to run with sudo
refuse_run_as_root() refuse_run_as_root()
@@ -1090,24 +1138,24 @@ def main():
'Try "./ns3 docs doxygen-no-build" or enable examples and tests.') 'Try "./ns3 docs doxygen-no-build" or enable examples and tests.')
exit(1) exit(1)
if args.check_profile: if args.show == "profile":
if build_profile: if build_profile:
print("Build profile: %s" % build_profile) print("Build profile: %s" % build_profile)
else: else:
project_not_configured() project_not_configured()
if args.check_version: if args.show == "version":
args.build = ["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
if args.run: if args.run:
# When running, default to not verbose # When running, default to not run_verbose
verbose = args.run_verbose run_verbose = args.run_verbose
# If not verbose, silence the rest of the script # If not run_verbose, silence the rest of the script
if not verbose: if not run_verbose:
output = subprocess.DEVNULL output = subprocess.DEVNULL
# Check whether we are only running or we need to build first # Check whether we are only running or we need to build first
@@ -1118,7 +1166,7 @@ def main():
target_to_run = None target_to_run = None
target_args = [] target_args = []
current_cmake_cache_folder = None current_cmake_cache_folder = None
if not args.check and (run_only or build_and_run): if run_only or build_and_run:
target_to_run = args.run target_to_run = args.run
if len(target_to_run) > 0: if len(target_to_run) > 0:
# While testing a weird case appeared where the target to run is between quotes, # While testing a weird case appeared where the target to run is between quotes,
@@ -1134,7 +1182,7 @@ def main():
# Get current CMake cache folder and CMake generator (used when reconfiguring) # Get current CMake cache folder and CMake generator (used when reconfiguring)
current_cmake_cache_folder, current_cmake_generator = search_cmake_cache(build_profile) current_cmake_cache_folder, current_cmake_generator = search_cmake_cache(build_profile)
if args.check_config: if args.show == "config":
check_config(current_cmake_cache_folder) check_config(current_cmake_cache_folder)
# We end things earlier if only checking the current project configuration # We end things earlier if only checking the current project configuration
return return
@@ -1217,7 +1265,7 @@ def main():
target_path = os.sep.join(target_path) target_path = os.sep.join(target_path)
return target_path return target_path
if not args.check and not args.shell and target_to_run and ".py" not in target_to_run: if not args.shell and target_to_run and ".py" not in target_to_run:
target_to_run = remove_overlapping_path(out_dir, target_to_run) target_to_run = remove_overlapping_path(out_dir, target_to_run)
# Waf doesn't add version prefix and build type suffix to the scratches, so we remove them # Waf doesn't add version prefix and build type suffix to the scratches, so we remove them
@@ -1237,7 +1285,7 @@ def main():
sudo_step(args, target_to_run, set(ns3_programs.values()[0]) if enable_sudo else set()) sudo_step(args, target_to_run, set(ns3_programs.values()[0]) if enable_sudo else set())
# Finally, we try to run it # Finally, we try to run it
if args.check or args.shell or run_only or build_and_run: if args.shell or run_only or build_and_run:
run_step(args, target_to_run, target_args) run_step(args, target_to_run, target_args)
return return

View File

@@ -19,7 +19,7 @@ find_external_library(
if(NOT if(NOT
${brite_FOUND} ${brite_FOUND}
) )
message(STATUS "Brite was not found") message(STATUS "Skipping src/brite")
return() return()
endif() endif()

View File

@@ -20,7 +20,7 @@ find_external_library(
if(NOT if(NOT
${click_FOUND} ${click_FOUND}
) )
message(STATUS "Click was not found") message(STATUS "Skipping src/click")
return() return()
endif() endif()

View File

@@ -15,17 +15,40 @@ if(${GSL_FOUND})
endif() endif()
# Check for dependencies and add sources accordingly # Check for dependencies and add sources accordingly
check_include_file_cxx( if(${CMAKE_VERSION}
"boost/units/quantity.hpp" VERSION_LESS
"3.11.0"
)
check_include_file_cxx(
boost/units/quantity.hpp
HAVE_BOOST_UNITS_QUANTITY HAVE_BOOST_UNITS_QUANTITY
) )
check_include_file_cxx( check_include_file_cxx(
"boost/units/systems/si.hpp" boost/units/systems/si.hpp
HAVE_BOOST_UNITS_SI HAVE_BOOST_UNITS_SI
) )
if(${HAVE_BOOST_UNITS_QUANTITY} if(${HAVE_BOOST_UNITS_QUANTITY}
AND ${HAVE_BOOST_UNITS_SI} 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( add_definitions(
-DHAVE_BOOST -DHAVE_BOOST
-DHAVE_BOOST_UNITS -DHAVE_BOOST_UNITS

View File

@@ -19,7 +19,7 @@ find_external_library(
if(NOT if(NOT
${openflow_FOUND} ${openflow_FOUND}
) )
message(STATUS "Openflow was not found") message(STATUS "Skipping src/openflow")
return() return()
endif() endif()

View File

@@ -1,4 +1,4 @@
include_directories(${PYTHON_INCLUDE_DIRS}) include_directories(${Python3_INCLUDE_DIRS})
build_lib( build_lib(
LIBNAME visualizer LIBNAME visualizer
@@ -6,7 +6,7 @@ build_lib(
model/visual-simulator-impl.cc model/visual-simulator-impl.cc
HEADER_FILES model/pyviz.h HEADER_FILES model/pyviz.h
LIBRARIES_TO_LINK LIBRARIES_TO_LINK
${PYTHON_LIBRARIES} ${Python3_LIBRARIES}
${libcore} ${libcore}
${libinternet} ${libinternet}
${libwifi} ${libwifi}

View File

@@ -313,28 +313,28 @@ class NS3CommonSettingsTestCase(unittest.TestCase):
def test_03_CheckConfig(self): def test_03_CheckConfig(self):
"""! """!
Test only passing --check-config argument to ns3 Test only passing 'show config' argument to ns3
@return None @return None
""" """
return_code, stdout, stderr = run_ns3("--check-config") return_code, stdout, stderr = run_ns3("show config")
self.assertEqual(return_code, 1) 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_04_CheckProfile(self): def test_04_CheckProfile(self):
"""! """!
Test only passing --check-profile argument to ns3 Test only passing 'show profile' argument to ns3
@return None @return None
""" """
return_code, stdout, stderr = run_ns3("--check-profile") return_code, stdout, stderr = run_ns3("show profile")
self.assertEqual(return_code, 1) 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_05_CheckVersion(self): def test_05_CheckVersion(self):
"""! """!
Test only passing --check-version argument to ns3 Test only passing 'show version' argument to ns3
@return None @return None
""" """
return_code, stdout, stderr = run_ns3("--check-version") return_code, stdout, stderr = run_ns3("show version")
self.assertEqual(return_code, 1) 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)
@@ -773,31 +773,31 @@ class NS3ConfigureTestCase(NS3BaseTestCase):
def test_10_CheckConfig(self): def test_10_CheckConfig(self):
"""! """!
Test passing --check-config argument to ns3 to get the configuration table Test passing 'show config' argument to ns3 to get the configuration table
@return None @return None
""" """
return_code, stdout, stderr = run_ns3("--check-config") return_code, stdout, stderr = run_ns3("show config")
self.assertEqual(return_code, 0) self.assertEqual(return_code, 0)
self.assertIn("Summary of optional NS-3 features", stdout) self.assertIn("Summary of optional NS-3 features", stdout)
def test_11_CheckProfile(self): def test_11_CheckProfile(self):
"""! """!
Test passing --check-profile argument to ns3 to get the build profile Test passing 'show profile' argument to ns3 to get the build profile
@return None @return None
""" """
return_code, stdout, stderr = run_ns3("--check-profile") return_code, stdout, stderr = run_ns3("show profile")
self.assertEqual(return_code, 0) self.assertEqual(return_code, 0)
self.assertIn("Build profile: debug", stdout) self.assertIn("Build profile: default", stdout)
def test_12_CheckVersion(self): def test_12_CheckVersion(self):
"""! """!
Test passing --check-version argument to ns3 to get the build version Test passing 'show version' argument to ns3 to get the build version
@return None @return None
""" """
return_code, _, _ = run_ns3("configure -G \"Unix Makefiles\" --enable-build-version") return_code, _, _ = run_ns3("configure -G \"Unix Makefiles\" --enable-build-version")
self.assertEqual(return_code, 0) self.assertEqual(return_code, 0)
return_code, stdout, stderr = run_ns3("--check-version") return_code, stdout, stderr = run_ns3("show version")
self.assertEqual(return_code, 0) self.assertEqual(return_code, 0)
self.assertIn("ns-3 version:", stdout) self.assertIn("ns-3 version:", stdout)
@@ -1657,15 +1657,7 @@ class NS3ExpectedUseTestCase(NS3BaseTestCase):
self.assertIn(cmake_build_target_command(target="doxygen"), stdout) self.assertIn(cmake_build_target_command(target="doxygen"), stdout)
self.assertIn("Built target doxygen", stdout) self.assertIn("Built target doxygen", stdout)
def test_14_Check(self): def test_14_EnableSudo(self):
"""!
Test if ns3 --check is working as expected
@return None
"""
return_code, stdout, stderr = run_ns3("--check")
self.assertEqual(return_code, 0)
def test_15_EnableSudo(self):
"""! """!
Try to set ownership of scratch-simulator from current user to root, Try to set ownership of scratch-simulator from current user to root,
and change execution permissions and change execution permissions
@@ -1742,7 +1734,7 @@ 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): def test_15_CommandTemplate(self):
"""! """!
Check if command template is working Check if command template is working
@return None @return None
@@ -1768,7 +1760,7 @@ class NS3ExpectedUseTestCase(NS3BaseTestCase):
self.assertIn("sample-simulator --PrintVersion", stdout4) self.assertIn("sample-simulator --PrintVersion", stdout4)
self.assertIn("sample-simulator --PrintVersion", stdout5) self.assertIn("sample-simulator --PrintVersion", stdout5)
def test_17_ForwardArgumentsToRunTargets(self): def test_16_ForwardArgumentsToRunTargets(self):
"""! """!
Check if all flavors of different argument passing to Check if all flavors of different argument passing to
executable targets are working executable targets are working
@@ -1825,7 +1817,7 @@ class NS3ExpectedUseTestCase(NS3BaseTestCase):
self.assertIn("To forward configuration or runtime options, put them after '--'", stderr0) self.assertIn("To forward configuration or runtime options, put them after '--'", stderr0)
self.assertIn("To forward configuration or runtime options, put them after '--'", stderr1) self.assertIn("To forward configuration or runtime options, put them after '--'", stderr1)
def test_18_RunNoBuildLldb(self): def test_17_RunNoBuildLldb(self):
"""! """!
Test if scratch simulator is executed through lldb Test if scratch simulator is executed through lldb
@return None @return None