diff --git a/CMakeLists.txt b/CMakeLists.txt index 9dc7caeda..27c463b9a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,6 +45,7 @@ option(NS3_CLANG_TIDY "Use clang-tidy static analysis" OFF) option(NS3_CLANG_TIMETRACE "Collect compilation statistics to analyze the build process" OFF ) +option(NS3_COLORED_OUTPUT "Colorize CMake messages" OFF) option(NS3_COVERAGE "Enable code coverage measurements and report generation" OFF ) diff --git a/build-support/3rd-party/colored-messages.cmake b/build-support/3rd-party/colored-messages.cmake new file mode 100644 index 000000000..bb7e69ef4 --- /dev/null +++ b/build-support/3rd-party/colored-messages.cmake @@ -0,0 +1,95 @@ +# Copyright (c) 2013 Fraser Hutchison +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License version 2 as published by the Free +# Software Foundation; +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, write to the Free Software Foundation, Inc., 59 Temple +# Place, Suite 330, Boston, MA 02111-1307 USA +# cmake-format: off +# +# Author: Fraser Hutchison +# Modified by: Gabriel Ferreira +# +# Original code: +# https://stackoverflow.com/a/19578320 +# Used with permission of the author: +# https://gitlab.com/nsnam/ns-3-dev/-/merge_requests/913#note_884829396 +# cmake-format: on + +# Set empty values for colors +set(ColourReset) +set(Red) +set(Green) +set(Yellow) +set(Blue) +set(Magenta) +set(Cyan) +set(White) +set(BoldRed) +set(BoldGreen) +set(BoldYellow) +set(BoldBlue) +set(BoldMagenta) +set(BoldCyan) +set(BoldWhite) + +# Custom message types fallback when not colorized +set(HIGHLIGHTED_STATUS STATUS) + +if(${NS3_COLORED_OUTPUT} OR "$ENV{CLICOLOR}") + if(NOT WIN32) + # When colorized, set color values + string(ASCII 27 Esc) + set(ColourReset "${Esc}[0m") + set(ColourBold "${Esc}[1m") + set(Red "${Esc}[31m") + set(Green "${Esc}[32m") + set(Yellow "${Esc}[33m") + set(Blue "${Esc}[34m") + set(Magenta "${Esc}[35m") + set(Cyan "${Esc}[36m") + set(White "${Esc}[37m") + set(BoldRed "${Esc}[1;31m") + set(BoldGreen "${Esc}[1;32m") + set(BoldYellow "${Esc}[1;33m") + set(BoldBlue "${Esc}[1;34m") + set(BoldMagenta "${Esc}[1;35m") + set(BoldCyan "${Esc}[1;36m") + set(BoldWhite "${Esc}[1;37m") + endif() + + # Set custom message type when colorized + set(HIGHLIGHTED_STATUS HIGHLIGHTED_STATUS) + + # Replace the default message macro with a custom colored one + function(message) + list(GET ARGV 0 MessageType) + if((${MessageType} STREQUAL FATAL_ERROR) OR (${MessageType} STREQUAL + SEND_ERROR) + ) + list(REMOVE_AT ARGV 0) + _message(${MessageType} "${BoldRed}${ARGV}${ColourReset}") + elseif(MessageType STREQUAL WARNING) + list(REMOVE_AT ARGV 0) + _message(${MessageType} "${BoldYellow}${ARGV}${ColourReset}") + elseif(MessageType STREQUAL AUTHOR_WARNING) + list(REMOVE_AT ARGV 0) + _message(${MessageType} "${BoldCyan}${ARGV}${ColourReset}") + elseif(MessageType STREQUAL HIGHLIGHTED_STATUS) # Custom message type + list(REMOVE_AT ARGV 0) + _message(STATUS "${Yellow}${ARGV}${ColourReset}") + elseif(MessageType STREQUAL STATUS) + list(REMOVE_AT ARGV 0) + _message(${MessageType} "${ARGV}") + else() + _message(${ARGV}) + endif() + endfunction() +endif() diff --git a/build-support/custom-modules/ns3-configtable.cmake b/build-support/custom-modules/ns3-configtable.cmake index 924ab863d..df276b970 100644 --- a/build-support/custom-modules/ns3-configtable.cmake +++ b/build-support/custom-modules/ns3-configtable.cmake @@ -58,9 +58,9 @@ macro(check_on_or_off user_config_switch confirmation_flag) if(${user_config_switch}) if(${confirmation_flag}) - string(APPEND out "ON\n") + string(APPEND out "${Green}ON${ColourReset}\n") else() - string(APPEND out "OFF (missing dependency)\n") + string(APPEND out "${Red}OFF (missing dependency)${ColourReset}\n") endif() else() string(APPEND out "OFF (not requested)\n") diff --git a/build-support/custom-modules/ns3-contributions.cmake b/build-support/custom-modules/ns3-contributions.cmake index 8d43e8478..77e7dbe63 100644 --- a/build-support/custom-modules/ns3-contributions.cmake +++ b/build-support/custom-modules/ns3-contributions.cmake @@ -30,8 +30,8 @@ macro(process_contribution contribution_list) message(STATUS "Processing ${folder}") add_subdirectory(${folder}) else() - message( - STATUS "Skipping ${folder} : it does not contain a CMakeLists.txt file" + message(${HIGHLIGHTED_STATUS} + "Skipping ${folder} : it does not contain a CMakeLists.txt file" ) endif() endforeach() diff --git a/build-support/macros-and-definitions.cmake b/build-support/macros-and-definitions.cmake index 487969ebb..58a83f931 100644 --- a/build-support/macros-and-definitions.cmake +++ b/build-support/macros-and-definitions.cmake @@ -36,6 +36,10 @@ option(NS3_ENABLE_SUDO "Set executables ownership to root and enable the SUID flag" OFF ) +# Replace default CMake messages (logging) with custom colored messages as early +# as possible +include(${PROJECT_SOURCE_DIR}/build-support/3rd-party/colored-messages.cmake) + # WSLv1 doesn't support tap features if(EXISTS "/proc/version") file(READ "/proc/version" CMAKE_LINUX_DISTRO) @@ -171,6 +175,12 @@ if((NOT CLANG) AND ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")) set(CLANG TRUE) endif() +if(CLANG) + if(${NS3_COLORED_OUTPUT} OR "$ENV{CLICOLOR}") + add_definitions(-fcolor-diagnostics) # colorize clang++ output + endif() +endif() + set(GCC FALSE) if("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS ${GNU_MinVersion}) @@ -181,6 +191,9 @@ if("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") endif() set(GCC TRUE) add_definitions(-fno-semantic-interposition) + if(${NS3_COLORED_OUTPUT} OR "$ENV{CLICOLOR}") + add_definitions(-fdiagnostics-color=always) # colorize g++ output + endif() endif() unset(below_minimum_msg) @@ -539,7 +552,7 @@ macro(process_options) if(${SQLite3_FOUND}) set(ENABLE_SQLITE True) else() - message(STATUS "SQLite was not found") + message(${HIGHLIGHTED_STATUS} "SQLite was not found") endif() endif() @@ -616,17 +629,23 @@ macro(process_options) if(${NS3_GTK3}) find_package(HarfBuzz QUIET) if(NOT ${HarfBuzz_FOUND}) - message(STATUS "Harfbuzz is required by GTK3 and was not found.") + message(${HIGHLIGHTED_STATUS} + "Harfbuzz is required by GTK3 and was not found." + ) else() set(CMAKE_SUPPRESS_DEVELOPER_WARNINGS 1 CACHE BOOL "") find_package(GTK3 QUIET) unset(CMAKE_SUPPRESS_DEVELOPER_WARNINGS CACHE) if(NOT ${GTK3_FOUND}) - message(STATUS "GTK3 was not found. Continuing without it.") + message(${HIGHLIGHTED_STATUS} + "GTK3 was not found. Continuing without it." + ) else() if(${GTK3_VERSION} VERSION_LESS 3.22) set(GTK3_FOUND FALSE) - message(STATUS "GTK3 found with incompatible version ${GTK3_VERSION}") + message(${HIGHLIGHTED_STATUS} + "GTK3 found with incompatible version ${GTK3_VERSION}" + ) else() message(STATUS "GTK3 was found.") endif() @@ -648,7 +667,9 @@ macro(process_options) else() find_package(LibXml2 QUIET) if(NOT ${LIBXML2_FOUND}) - message(STATUS "LibXML2 was not found. Continuing without it.") + message(${HIGHLIGHTED_STATUS} + "LibXML2 was not found. Continuing without it." + ) else() message(STATUS "LibXML2 was found.") add_definitions(-DHAVE_LIBXML2) @@ -719,12 +740,14 @@ macro(process_options) if(${Python3_Development_FOUND}) set(Python3_FOUND TRUE) else() - message(STATUS "Python: development libraries were not found") + message(${HIGHLIGHTED_STATUS} + "Python: development libraries were not found" + ) endif() else() message( - STATUS - "Python: an incompatible version of Python was found, python bindings will be disabled" + ${HIGHLIGHTED_STATUS} + "Python: an incompatible version of Python was found, python bindings will be disabled" ) endif() @@ -732,15 +755,15 @@ macro(process_options) if(${NS3_PYTHON_BINDINGS}) if(NOT ${Python3_FOUND}) message( - STATUS - "Bindings: python bindings require Python, but it could not be found" + ${HIGHLIGHTED_STATUS} + "Bindings: python bindings require Python, but it could not be found" ) else() check_python_packages("pybindgen" missing_packages) if(missing_packages) message( - STATUS - "Bindings: python bindings disabled due to the following missing dependencies: ${missing_packages}" + ${HIGHLIGHTED_STATUS} + "Bindings: python bindings disabled due to the following missing dependencies: ${missing_packages}" ) else() set(ENABLE_PYTHON_BINDINGS ON) @@ -757,8 +780,8 @@ macro(process_options) if(${NS3_SCAN_PYTHON_BINDINGS}) if(NOT ${Python3_FOUND}) message( - STATUS - "Bindings: scanning python bindings require Python, but it could not be found" + ${HIGHLIGHTED_STATUS} + "Bindings: scanning python bindings require Python, but it could not be found" ) else() # Check if pybindgen, pygccxml, cxxfilt and castxml are installed @@ -779,8 +802,8 @@ macro(process_options) # If packages were not found, print message if(missing_packages) message( - STATUS - "Bindings: scanning of python bindings disabled due to the following missing dependencies: ${missing_packages}" + ${HIGHLIGHTED_STATUS} + "Bindings: scanning of python bindings disabled due to the following missing dependencies: ${missing_packages}" ) else() set(ENABLE_SCAN_PYTHON_BINDINGS ON) @@ -794,7 +817,7 @@ macro(process_options) set(ENABLE_VISUALIZER FALSE) if(${NS3_VISUALIZER}) if((NOT ${ENABLE_PYTHON_BINDINGS}) OR (NOT ${Python3_FOUND})) - message(STATUS "Visualizer requires Python bindings") + message(${HIGHLIGHTED_STATUS} "Visualizer requires Python bindings") else() set(ENABLE_VISUALIZER TRUE) endif() @@ -803,8 +826,7 @@ macro(process_options) if(${NS3_COVERAGE} AND (NOT ${ENABLE_TESTS} OR NOT ${ENABLE_EXAMPLES})) message( FATAL_ERROR - "Code coverage requires examples and tests.\n" - "Try reconfiguring CMake with -DNS3_TESTS=ON -DNS3_EXAMPLES=ON" + "Code coverage requires examples and tests.\nTry reconfiguring CMake with -DNS3_TESTS=ON -DNS3_EXAMPLES=ON" ) endif() @@ -834,7 +856,7 @@ macro(process_options) if(${NS3_MPI}) find_package(MPI QUIET) if(NOT ${MPI_FOUND}) - message(STATUS "MPI was not found. Continuing without it.") + message(${HIGHLIGHTED_STATUS} "MPI was not found. Continuing without it.") else() message(STATUS "MPI was found.") add_definitions(-DNS3_MPI) @@ -862,7 +884,7 @@ macro(process_options) if(${NS3_GSL}) find_package(GSL QUIET) if(NOT ${GSL_FOUND}) - message(STATUS "GSL was not found. Continuing without it.") + message(${HIGHLIGHTED_STATUS} "GSL was not found. Continuing without it.") else() message(STATUS "GSL was found.") add_definitions(-DHAVE_GSL) @@ -873,7 +895,9 @@ macro(process_options) find_package(Gnuplot-ios) # Not sure what package would contain the correct # header/library if(NOT ${GNUPLOT_FOUND}) - message(STATUS "GNUPLOT was not found. Continuing without it.") + message(${HIGHLIGHTED_STATUS} + "GNUPLOT was not found. Continuing without it." + ) else() message(STATUS "GNUPLOT was found.") include_directories(${GNUPLOT_INCLUDE_DIRS}) @@ -888,8 +912,8 @@ macro(process_options) check_deps("" "doxygen;dot;dia" doxygen_docs_missing_deps) if(doxygen_docs_missing_deps) message( - STATUS - "docs: doxygen documentation not enabled due to missing dependencies: ${doxygen_docs_missing_deps}" + ${HIGHLIGHTED_STATUS} + "docs: doxygen documentation not enabled due to missing dependencies: ${doxygen_docs_missing_deps}" ) # cmake-format: off set(doxygen_missing_msg @@ -992,8 +1016,8 @@ macro(process_options) ) if(sphinx_docs_missing_deps) message( - STATUS - "docs: sphinx documentation not enabled due to missing dependencies: ${sphinx_docs_missing_deps}" + ${HIGHLIGHTED_STATUS} + "docs: sphinx documentation not enabled due to missing dependencies: ${sphinx_docs_missing_deps}" ) # cmake-format: off set(sphinx_missing_msg @@ -1058,7 +1082,9 @@ macro(process_options) if(HAVE_UINT128_T OR HAVE___UINT128_T) set(INT64X64_USE_128 TRUE) else() - message(STATUS "Int128 was not found. Falling back to Cairo.") + message(${HIGHLIGHTED_STATUS} + "Int128 was not found. Falling back to Cairo." + ) set(NS3_INT64X64 "CAIRO") endif() endif() @@ -1328,23 +1354,36 @@ function(copy_headers_before_building_lib libname outputdir headers visibility) set(batch_symlinks) foreach(header ${headers}) # Copy header to output directory on changes -> too darn slow - #configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${header} ${outputdir}/ COPYONLY) + # configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${header} ${outputdir}/ + # COPYONLY) get_filename_component( - header_name ${CMAKE_CURRENT_SOURCE_DIR}/${header} - NAME + header_name ${CMAKE_CURRENT_SOURCE_DIR}/${header} NAME ) - # CMake 3.13 cannot create symlinks on Windows, so we use stub headers as a fallback - if (WIN32 AND (${CMAKE_VERSION} VERSION_LESS "3.13.0")) - # Create a stub header in the output directory, including the real header inside their - # respective module + # CMake 3.13 cannot create symlinks on Windows, so we use stub headers as a + # fallback + if(WIN32 AND (${CMAKE_VERSION} VERSION_LESS "3.13.0")) + # Create a stub header in the output directory, including the real header + # inside their respective module - file(WRITE ${outputdir}/${header_name} "#include \"${CMAKE_CURRENT_SOURCE_DIR}/${header}\"\n") + file(WRITE ${outputdir}/${header_name} + "#include \"${CMAKE_CURRENT_SOURCE_DIR}/${header}\"\n" + ) else() - # Create a symlink in the output directory to the original header - # Calling execute_process for each symlink is too slow too, so we create a batch with all headers - #execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_CURRENT_SOURCE_DIR}/${header} ${outputdir}/${header_name}) - set(batch_symlinks ${batch_symlinks} COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_CURRENT_SOURCE_DIR}/${header} ${outputdir}/${header_name}) + # Create a symlink in the output directory to the original header Calling + # execute_process for each symlink is too slow too, so we create a batch + # with all headers execute_process(COMMAND ${CMAKE_COMMAND} -E + # create_symlink ${CMAKE_CURRENT_SOURCE_DIR}/${header} + # ${outputdir}/${header_name}) + set(batch_symlinks + ${batch_symlinks} + COMMAND + ${CMAKE_COMMAND} + -E + create_symlink + ${CMAKE_CURRENT_SOURCE_DIR}/${header} + ${outputdir}/${header_name} + ) endif() endforeach() @@ -1506,8 +1545,8 @@ function(recursive_dependency module_name) set(contrib TRUE) else() set(cmakelists_content "") - message( - STATUS "The CMakeLists.txt file for module ${module_name} was not found." + message(${HIGHLIGHTED_STATUS} + "The CMakeLists.txt file for module ${module_name} was not found." ) endif() @@ -1992,7 +2031,7 @@ function(find_external_library) endif() if(NOT ${FIND_LIB_QUIET}) - message(STATUS "${status_message}") + message(${HIGHLIGHTED_STATUS} "${status_message}") endif() endfunction() diff --git a/ns3 b/ns3 index 514f38cc1..360f594f6 100755 --- a/ns3 +++ b/ns3 @@ -1125,6 +1125,9 @@ def main(): # Refuse to run with sudo refuse_run_as_root() + # Enable colorized output for CMake and GCC/Clang + os.environ["CLICOLOR"] = "1" + # Parse arguments args = parse_args(sys.argv[1:]) atexit.register(exit_handler, dry_run=args.dry_run) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0cf84cf24..640bab2ab 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -16,8 +16,8 @@ foreach(libname ${libs}) add_subdirectory(${libname}) else() message( - STATUS - "Skipping src/${libname} : it does not contain a CMakeLists.txt file" + ${HIGHLIGHTED_STATUS} + "Skipping src/${libname} : it does not contain a CMakeLists.txt file" ) endif() endforeach() diff --git a/src/brite/CMakeLists.txt b/src/brite/CMakeLists.txt index c44985927..8ca0d591b 100644 --- a/src/brite/CMakeLists.txt +++ b/src/brite/CMakeLists.txt @@ -21,7 +21,10 @@ if((NOT OR (NOT ${brite_FOUND}) ) - message(STATUS "Skipping src/brite") + message( + ${HIGHLIGHTED_STATUS} + "Skipping src/brite" + ) return() endif() diff --git a/src/click/CMakeLists.txt b/src/click/CMakeLists.txt index 7409033c7..f094a67cf 100644 --- a/src/click/CMakeLists.txt +++ b/src/click/CMakeLists.txt @@ -22,7 +22,10 @@ if((NOT AND (NOT ${click_FOUND}) ) - message(STATUS "Skipping src/click") + message( + ${HIGHLIGHTED_STATUS} + "Skipping src/click" + ) return() endif() diff --git a/src/openflow/CMakeLists.txt b/src/openflow/CMakeLists.txt index ccdb9ce16..876c92509 100644 --- a/src/openflow/CMakeLists.txt +++ b/src/openflow/CMakeLists.txt @@ -21,7 +21,10 @@ if((NOT AND (NOT ${openflow_FOUND}) ) - message(STATUS "Skipping src/openflow") + message( + ${HIGHLIGHTED_STATUS} + "Skipping src/openflow" + ) return() endif()