diff --git a/Auxiliary/vim/syntax/cmake.vim b/Auxiliary/vim/syntax/cmake.vim index 381d97c213..703144bbe4 100644 --- a/Auxiliary/vim/syntax/cmake.vim +++ b/Auxiliary/vim/syntax/cmake.vim @@ -705,6 +705,7 @@ syn keyword cmakeVariable contained \ CMAKE_CODEBLOCKS_COMPILER_ID \ CMAKE_CODEBLOCKS_EXCLUDE_EXTERNAL_FILES \ CMAKE_CODELITE_USE_TARGETS + \ CMAKE_COLOR_DIAGNOSTICS \ CMAKE_COLOR_MAKEFILE \ CMAKE_COMMAND \ CMAKE_COMPILER_2005 diff --git a/Help/envvar/CMAKE_COLOR_DIAGNOSTICS.rst b/Help/envvar/CMAKE_COLOR_DIAGNOSTICS.rst new file mode 100644 index 0000000000..d3d0aa94a6 --- /dev/null +++ b/Help/envvar/CMAKE_COLOR_DIAGNOSTICS.rst @@ -0,0 +1,9 @@ +CMAKE_COLOR_DIAGNOSTICS +----------------------- + +.. versionadded:: 3.24 + +.. include:: ENV_VAR.txt + +Specifies a default value for the :variable:`CMAKE_COLOR_DIAGNOSTICS` variable +when there is no explicit value given on the first run. diff --git a/Help/manual/cmake-env-variables.7.rst b/Help/manual/cmake-env-variables.7.rst index 0799fddb67..fc142623fe 100644 --- a/Help/manual/cmake-env-variables.7.rst +++ b/Help/manual/cmake-env-variables.7.rst @@ -31,6 +31,7 @@ Environment Variables that Control the Build /envvar/CMAKE_APPLE_SILICON_PROCESSOR /envvar/CMAKE_BUILD_PARALLEL_LEVEL /envvar/CMAKE_BUILD_TYPE + /envvar/CMAKE_COLOR_DIAGNOSTICS /envvar/CMAKE_CONFIGURATION_TYPES /envvar/CMAKE_CONFIG_TYPE /envvar/CMAKE_EXPORT_COMPILE_COMMANDS diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst index ffebfffd4e..f2fef546b6 100644 --- a/Help/manual/cmake-variables.7.rst +++ b/Help/manual/cmake-variables.7.rst @@ -172,6 +172,7 @@ Variables that Change Behavior /variable/CMAKE_CODEBLOCKS_COMPILER_ID /variable/CMAKE_CODEBLOCKS_EXCLUDE_EXTERNAL_FILES /variable/CMAKE_CODELITE_USE_TARGETS + /variable/CMAKE_COLOR_DIAGNOSTICS /variable/CMAKE_COLOR_MAKEFILE /variable/CMAKE_CONFIGURATION_TYPES /variable/CMAKE_DEPENDS_IN_PROJECT_ONLY diff --git a/Help/release/dev/color-diagnostics.rst b/Help/release/dev/color-diagnostics.rst new file mode 100644 index 0000000000..8e0e2255a5 --- /dev/null +++ b/Help/release/dev/color-diagnostics.rst @@ -0,0 +1,10 @@ +color-diagnostics +----------------- + +* The :variable:`CMAKE_COLOR_DIAGNOSTICS` variable was added to control + color diagnostics generated by compilers. This variable also controls + color buildsystem messages with :ref:`Makefile Generators`, replacing + :variable:`CMAKE_COLOR_MAKEFILE`. + + The :envvar:`CMAKE_COLOR_DIAGNOSTICS` environment was added to set + a default value for :variable:`CMAKE_COLOR_DIAGNOSTICS`. diff --git a/Help/variable/CMAKE_COLOR_DIAGNOSTICS.rst b/Help/variable/CMAKE_COLOR_DIAGNOSTICS.rst new file mode 100644 index 0000000000..a72c9e1999 --- /dev/null +++ b/Help/variable/CMAKE_COLOR_DIAGNOSTICS.rst @@ -0,0 +1,37 @@ +CMAKE_COLOR_DIAGNOSTICS +----------------------- + +.. versionadded:: 3.24 + +Enable color diagnostics throughout. + +This variable uses three states: ``ON``, ``OFF`` and not defined. + +When not defined: + +* :ref:`Makefile Generators` initialize the :variable:`CMAKE_COLOR_MAKEFILE` + variable to ``ON``. It controls color buildsystem messages. + +* GNU/Clang compilers are not invoked with any color diagnostics flag. + +When ``ON``: + +* :ref:`Makefile Generators` produce color buildsystem messages by default. + :variable:`CMAKE_COLOR_MAKEFILE` is not initialized, but may be + explicitly set to ``OFF`` to disable color buildsystem messages. + +* GNU/Clang compilers are invoked with a flag enabling color diagnostics + (``-fcolor-diagnostics``). + +When ``OFF``: + +* :ref:`Makefile Generators` do not produce color buildsystem messages by + default. :variable:`CMAKE_COLOR_MAKEFILE` is not initialized, but may be + explicitly set to ``ON`` to enable color buildsystem messages. + +* GNU/Clang compilers are invoked with a flag disabling color diagnostics + (``-fno-color-diagnostics``). + +If the :envvar:`CMAKE_COLOR_DIAGNOSTICS` environment variable is set, its +value is used. Otherwise, ``CMAKE_COLOR_DIAGNOSTICS`` is not defined by +default. diff --git a/Modules/CMakeGenericSystem.cmake b/Modules/CMakeGenericSystem.cmake index 6e75facff3..e2925dc98e 100644 --- a/Modules/CMakeGenericSystem.cmake +++ b/Modules/CMakeGenericSystem.cmake @@ -47,11 +47,16 @@ set (CMAKE_SKIP_INSTALL_RPATH "NO" CACHE BOOL set(CMAKE_VERBOSE_MAKEFILE FALSE CACHE BOOL "If this value is on, makefiles will be generated without the .SILENT directive, and all commands will be echoed to the console during the make. This is useful for debugging only. With Visual Studio IDE projects all commands are done without /nologo.") +if(DEFINED ENV{CMAKE_COLOR_DIAGNOSTICS} AND NOT DEFINED CACHE{CMAKE_COLOR_DIAGNOSTICS}) + set(CMAKE_COLOR_DIAGNOSTICS $ENV{CMAKE_COLOR_DIAGNOSTICS} CACHE BOOL "Enable colored diagnostics throughout.") +endif() + if(CMAKE_GENERATOR MATCHES "Make") - set(CMAKE_COLOR_MAKEFILE ON CACHE BOOL - "Enable/Disable color output during build." - ) + if(NOT DEFINED CMAKE_COLOR_DIAGNOSTICS) + set(CMAKE_COLOR_MAKEFILE ON CACHE BOOL "Enable/Disable color output during build.") + endif() mark_as_advanced(CMAKE_COLOR_MAKEFILE) + if(DEFINED CMAKE_RULE_MESSAGES) set_property(GLOBAL PROPERTY RULE_MESSAGES ${CMAKE_RULE_MESSAGES}) endif() diff --git a/Modules/Compiler/Clang.cmake b/Modules/Compiler/Clang.cmake index f885eb0234..df115d3aac 100644 --- a/Modules/Compiler/Clang.cmake +++ b/Modules/Compiler/Clang.cmake @@ -114,6 +114,12 @@ else() endif() set(CMAKE_${lang}_COMPILE_OPTIONS_USE_PCH -Xclang -include-pch -Xclang -Xclang -include -Xclang ) set(CMAKE_${lang}_COMPILE_OPTIONS_CREATE_PCH -Xclang -emit-pch -Xclang -include -Xclang -x ${__pch_header_${lang}}) + + # '-fcolor-diagnostics' introduced since Clang 2.6 + if(CMAKE_${lang}_COMPILER_VERSION VERSION_GREATER_EQUAL 2.6) + set(CMAKE_${lang}_COMPILE_OPTIONS_COLOR_DIAGNOSTICS "-fcolor-diagnostics") + set(CMAKE_${lang}_COMPILE_OPTIONS_COLOR_DIAGNOSTICS_OFF "-fno-color-diagnostics") + endif() endmacro() endif() diff --git a/Modules/Compiler/GNU.cmake b/Modules/Compiler/GNU.cmake index 928e7263fc..2eef5323a0 100644 --- a/Modules/Compiler/GNU.cmake +++ b/Modules/Compiler/GNU.cmake @@ -119,4 +119,11 @@ macro(__compiler_gnu lang) set(CMAKE_${lang}_COMPILE_OPTIONS_USE_PCH -include ) set(CMAKE_${lang}_COMPILE_OPTIONS_CREATE_PCH -x ${__pch_header_${lang}} -include ) endif() + + # '-fdiagnostics-color=always' introduced since GCC 4.9 + # https://gcc.gnu.org/gcc-4.9/changes.html + if(CMAKE_${lang}_COMPILER_VERSION VERSION_GREATER_EQUAL 4.9) + set(CMAKE_${lang}_COMPILE_OPTIONS_COLOR_DIAGNOSTICS "-fdiagnostics-color=always") + set(CMAKE_${lang}_COMPILE_OPTIONS_COLOR_DIAGNOSTICS_OFF "-fno-diagnostics-color") + endif() endmacro() diff --git a/Source/cmGhsMultiTargetGenerator.cxx b/Source/cmGhsMultiTargetGenerator.cxx index c853c5023f..a2d64aaa73 100644 --- a/Source/cmGhsMultiTargetGenerator.cxx +++ b/Source/cmGhsMultiTargetGenerator.cxx @@ -182,6 +182,7 @@ void cmGhsMultiTargetGenerator::SetCompilerFlags(std::string const& config, language, config); this->LocalGenerator->AddVisibilityPresetFlags( flags, this->GeneratorTarget, language); + this->LocalGenerator->AddColorDiagnosticsFlags(flags, language); // Append old-style preprocessor definition flags. if (this->Makefile->GetDefineFlags() != " ") { diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 3976c4214e..4fa7d4f546 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -1609,6 +1609,7 @@ std::vector> cmLocalGenerator::GetTargetCompileFlags( this->AddCMP0018Flags(compileFlags, target, lang, config); this->AddVisibilityPresetFlags(compileFlags, target, lang); + this->AddColorDiagnosticsFlags(compileFlags, lang); this->AppendFlags(compileFlags, mf->GetDefineFlags()); this->AppendFlags(compileFlags, this->GetFrameworkFlags(lang, config, target)); @@ -2354,6 +2355,29 @@ void cmLocalGenerator::AddPositionIndependentFlags(std::string& flags, } } +void cmLocalGenerator::AddColorDiagnosticsFlags(std::string& flags, + const std::string& lang) +{ + cmValue diag = this->Makefile->GetDefinition("CMAKE_COLOR_DIAGNOSTICS"); + if (diag.IsSet()) { + std::string colorFlagName; + if (diag.IsOn()) { + colorFlagName = + cmStrCat("CMAKE_", lang, "_COMPILE_OPTIONS_COLOR_DIAGNOSTICS"); + } else { + colorFlagName = + cmStrCat("CMAKE_", lang, "_COMPILE_OPTIONS_COLOR_DIAGNOSTICS_OFF"); + } + + std::vector options; + this->Makefile->GetDefExpandList(colorFlagName, options); + + for (std::string const& option : options) { + this->AppendFlagEscape(flags, option); + } + } +} + void cmLocalGenerator::AddConfigVariableFlags(std::string& flags, const std::string& var, const std::string& config) diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h index 115a54a5fc..436a29e932 100644 --- a/Source/cmLocalGenerator.h +++ b/Source/cmLocalGenerator.h @@ -159,6 +159,7 @@ public: cmGeneratorTarget const* target, const std::string& lang, const std::string& config); + void AddColorDiagnosticsFlags(std::string& flags, const std::string& lang); //! Append flags to a string. virtual void AppendFlags(std::string& flags, const std::string& newFlags) const; diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index 7c4af7de25..97a275ae44 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -133,7 +133,11 @@ void cmLocalUnixMakefileGenerator3::Generate() // Record whether some options are enabled to avoid checking many // times later. if (!this->GetGlobalGenerator()->GetCMakeInstance()->GetIsInTryCompile()) { - this->ColorMakefile = this->Makefile->IsOn("CMAKE_COLOR_MAKEFILE"); + if (this->Makefile->IsSet("CMAKE_COLOR_MAKEFILE")) { + this->ColorMakefile = this->Makefile->IsOn("CMAKE_COLOR_MAKEFILE"); + } else { + this->ColorMakefile = this->Makefile->IsOn("CMAKE_COLOR_DIAGNOSTICS"); + } } this->SkipPreprocessedSourceRules = this->Makefile->IsOn("CMAKE_SKIP_PREPROCESSED_SOURCE_RULES"); diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index 82bc8c3fde..1deb75f974 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -278,6 +278,9 @@ endif() add_RunCMake_test(CMakeDependentOption) add_RunCMake_test(CMakeRoleGlobalProperty) add_RunCMake_test(CMakeRelease -DCMake_TEST_JQ=${CMake_TEST_JQ}) +if(CMAKE_GENERATOR MATCHES "Make|Ninja") + add_RunCMake_test(Color) +endif() if(UNIX AND "${CMAKE_GENERATOR}" MATCHES "Unix Makefiles|Ninja") add_RunCMake_test(CompilerChange) endif() diff --git a/Tests/RunCMake/Color/CMakeLists.txt b/Tests/RunCMake/Color/CMakeLists.txt new file mode 100644 index 0000000000..5ff8d3e0ff --- /dev/null +++ b/Tests/RunCMake/Color/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 3.23) +project(${RunCMake_TEST} NONE) +include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/Color/DiagCommon.cmake b/Tests/RunCMake/Color/DiagCommon.cmake new file mode 100644 index 0000000000..9a69317d7d --- /dev/null +++ b/Tests/RunCMake/Color/DiagCommon.cmake @@ -0,0 +1,9 @@ +enable_language(C) + +set(CMAKE_C_COMPILE_OPTIONS_COLOR_DIAGNOSTICS -DCOLOR_ON) +set(CMAKE_C_COMPILE_OPTIONS_COLOR_DIAGNOSTICS_OFF -DCOLOR_OFF) + +add_library(diag STATIC diag.c) +if(DEFINED EXPECT_COLOR) + target_compile_definitions(diag PRIVATE EXPECT_COLOR=${EXPECT_COLOR}) +endif() diff --git a/Tests/RunCMake/Color/DiagDefault.cmake b/Tests/RunCMake/Color/DiagDefault.cmake new file mode 100644 index 0000000000..5add9dc287 --- /dev/null +++ b/Tests/RunCMake/Color/DiagDefault.cmake @@ -0,0 +1,8 @@ +include(DiagCommon.cmake) + +if(DEFINED CMAKE_COLOR_DIAGNOSTICS) + message(FATAL_ERROR "CMAKE_COLOR_DIAGNOSTICS incorrectly defined.") +endif() +if(CMAKE_GENERATOR MATCHES "Make" AND NOT DEFINED CMAKE_COLOR_MAKEFILE) + message(FATAL_ERROR "CMAKE_COLOR_MAKEFILE incorrectly not defined.") +endif() diff --git a/Tests/RunCMake/Color/DiagOff.cmake b/Tests/RunCMake/Color/DiagOff.cmake new file mode 100644 index 0000000000..56657b06c4 --- /dev/null +++ b/Tests/RunCMake/Color/DiagOff.cmake @@ -0,0 +1,6 @@ +set(EXPECT_COLOR 0) +include(DiagCommon.cmake) + +if(DEFINED CMAKE_COLOR_MAKEFILE) + message(FATAL_ERROR "CMAKE_COLOR_MAKEFILE incorrectly defined.") +endif() diff --git a/Tests/RunCMake/Color/DiagOn.cmake b/Tests/RunCMake/Color/DiagOn.cmake new file mode 100644 index 0000000000..fbb6c705f5 --- /dev/null +++ b/Tests/RunCMake/Color/DiagOn.cmake @@ -0,0 +1,6 @@ +set(EXPECT_COLOR 1) +include(DiagCommon.cmake) + +if(DEFINED CMAKE_COLOR_MAKEFILE) + message(FATAL_ERROR "CMAKE_COLOR_MAKEFILE incorrectly defined.") +endif() diff --git a/Tests/RunCMake/Color/RunCMakeTest.cmake b/Tests/RunCMake/Color/RunCMakeTest.cmake new file mode 100644 index 0000000000..bb62d4c34c --- /dev/null +++ b/Tests/RunCMake/Color/RunCMakeTest.cmake @@ -0,0 +1,14 @@ +include(RunCMake) + +unset(ENV{CMAKE_COLOR_DIAGNOSTICS}) + +function(run_Diag case) + set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/Diag${case}-build") + run_cmake_with_options(Diag${case} ${ARGN}) + set(RunCMake_TEST_NO_CLEAN 1) + run_cmake_command(Diag${case}-build ${CMAKE_COMMAND} --build . --config Debug) +endfunction() + +run_Diag(On -DCMAKE_COLOR_DIAGNOSTICS=ON) +run_Diag(Off -DCMAKE_COLOR_DIAGNOSTICS=OFF) +run_Diag(Default) diff --git a/Tests/RunCMake/Color/diag.c b/Tests/RunCMake/Color/diag.c new file mode 100644 index 0000000000..7ff8304348 --- /dev/null +++ b/Tests/RunCMake/Color/diag.c @@ -0,0 +1,28 @@ +#ifdef EXPECT_COLOR +# if EXPECT_COLOR +# ifndef COLOR_ON +# error "COLOR_ON incorrectly not defined" +# endif +# ifdef COLOR_OFF +# error "COLOR_OFF incorrectly defined" +# endif +# else +# ifdef COLOR_ON +# error "COLOR_ON incorrectly defined" +# endif +# ifndef COLOR_OFF +# error "COLOR_OFF incorrectly not defined" +# endif +# endif +#else +# ifdef COLOR_ON +# error "COLOR_ON incorrectly defined" +# endif +# ifdef COLOR_OFF +# error "COLOR_OFF incorrectly defined" +# endif +#endif + +void diag(void) +{ +} diff --git a/Tests/RunCMake/CommandLine/EnvColorDefault.cmake b/Tests/RunCMake/CommandLine/EnvColorDefault.cmake new file mode 100644 index 0000000000..dc4bc98636 --- /dev/null +++ b/Tests/RunCMake/CommandLine/EnvColorDefault.cmake @@ -0,0 +1,6 @@ +if(DEFINED CMAKE_COLOR_DIAGNOSTICS) + message(FATAL_ERROR "CMAKE_COLOR_DIAGNOSTICS incorrectly defined.") +endif() +if(CMAKE_GENERATOR MATCHES "Make" AND NOT DEFINED CMAKE_COLOR_MAKEFILE) + message(FATAL_ERROR "CMAKE_COLOR_MAKEFILE incorrectly not defined.") +endif() diff --git a/Tests/RunCMake/CommandLine/EnvColorOn-stdout.txt b/Tests/RunCMake/CommandLine/EnvColorOn-stdout.txt new file mode 100644 index 0000000000..885925eb6a --- /dev/null +++ b/Tests/RunCMake/CommandLine/EnvColorOn-stdout.txt @@ -0,0 +1 @@ +-- CMAKE_COLOR_DIAGNOSTICS='ON' diff --git a/Tests/RunCMake/CommandLine/EnvColorOn.cmake b/Tests/RunCMake/CommandLine/EnvColorOn.cmake new file mode 100644 index 0000000000..af1235d506 --- /dev/null +++ b/Tests/RunCMake/CommandLine/EnvColorOn.cmake @@ -0,0 +1,4 @@ +message(STATUS "CMAKE_COLOR_DIAGNOSTICS='${CMAKE_COLOR_DIAGNOSTICS}'") +if(DEFINED CMAKE_COLOR_MAKEFILE) + message(FATAL_ERROR "CMAKE_COLOR_MAKEFILE incorrectly defined.") +endif() diff --git a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake index 951ba50d70..5b8c715282 100644 --- a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake +++ b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake @@ -445,6 +445,14 @@ function(run_EnvironmentToolchain) endfunction() run_EnvironmentToolchain() +function(run_EnvironmentColor) + set(ENV{CMAKE_COLOR_DIAGNOSTICS} "ON") + run_cmake(EnvColorOn) + unset(ENV{CMAKE_COLOR_DIAGNOSTICS}) + run_cmake(EnvColorDefault) +endfunction() +run_EnvironmentColor() + if(RunCMake_GENERATOR STREQUAL "Ninja") # Use a single build tree for a few tests without cleaning. set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/Build-build)