Add options to run clang-tidy with the compiler
Create a <LANG>_CLANG_TIDY target property (initialized by a CMAKE_<LANG>_CLANG_TIDY variable) to specify a clang-tidy command line to be run along with the compiler.
This commit is contained in:
parent
9ac11bc25d
commit
5e62444cff
|
@ -197,6 +197,7 @@ Properties on Targets
|
||||||
/prop_tgt/JOB_POOL_COMPILE
|
/prop_tgt/JOB_POOL_COMPILE
|
||||||
/prop_tgt/JOB_POOL_LINK
|
/prop_tgt/JOB_POOL_LINK
|
||||||
/prop_tgt/LABELS
|
/prop_tgt/LABELS
|
||||||
|
/prop_tgt/LANG_CLANG_TIDY
|
||||||
/prop_tgt/LANG_COMPILER_LAUNCHER
|
/prop_tgt/LANG_COMPILER_LAUNCHER
|
||||||
/prop_tgt/LANG_INCLUDE_WHAT_YOU_USE
|
/prop_tgt/LANG_INCLUDE_WHAT_YOU_USE
|
||||||
/prop_tgt/LANG_VISIBILITY_PRESET
|
/prop_tgt/LANG_VISIBILITY_PRESET
|
||||||
|
|
|
@ -259,6 +259,7 @@ Variables that Control the Build
|
||||||
/variable/CMAKE_INSTALL_RPATH
|
/variable/CMAKE_INSTALL_RPATH
|
||||||
/variable/CMAKE_INSTALL_RPATH_USE_LINK_PATH
|
/variable/CMAKE_INSTALL_RPATH_USE_LINK_PATH
|
||||||
/variable/CMAKE_IOS_INSTALL_COMBINED
|
/variable/CMAKE_IOS_INSTALL_COMBINED
|
||||||
|
/variable/CMAKE_LANG_CLANG_TIDY
|
||||||
/variable/CMAKE_LANG_COMPILER_LAUNCHER
|
/variable/CMAKE_LANG_COMPILER_LAUNCHER
|
||||||
/variable/CMAKE_LANG_INCLUDE_WHAT_YOU_USE
|
/variable/CMAKE_LANG_INCLUDE_WHAT_YOU_USE
|
||||||
/variable/CMAKE_LANG_VISIBILITY_PRESET
|
/variable/CMAKE_LANG_VISIBILITY_PRESET
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
<LANG>_CLANG_TIDY
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
This property is implemented only when ``<LANG>`` is ``C`` or ``CXX``.
|
||||||
|
|
||||||
|
Specify a :ref:`;-list <CMake Language Lists>` containing a command
|
||||||
|
line for the ``clang-tidy`` tool. The :ref:`Makefile Generators`
|
||||||
|
and the :generator:`Ninja` generator will run this tool along with the
|
||||||
|
compiler and report a warning if the tool reports any problems.
|
||||||
|
|
||||||
|
This property is initialized by the value of
|
||||||
|
the :variable:`CMAKE_<LANG>_CLANG_TIDY` variable if it is set
|
||||||
|
when a target is created.
|
|
@ -0,0 +1,7 @@
|
||||||
|
clang-tidy
|
||||||
|
----------
|
||||||
|
|
||||||
|
* A :prop_tgt:`<LANG>_CLANG_TIDY` target property and supporting
|
||||||
|
:variable:`CMAKE_<LANG>_CLANG_TIDY` variable were introduced to tell the
|
||||||
|
:ref:`Makefile Generators` and the :generator:`Ninja` generator to run
|
||||||
|
``clang-tidy`` along with the compiler for ``C`` and ``CXX`` languages.
|
|
@ -0,0 +1,6 @@
|
||||||
|
CMAKE_<LANG>_CLANG_TIDY
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
Default value for :prop_tgt:`<LANG>_CLANG_TIDY` target property.
|
||||||
|
This variable is used to initialize the property on each target as it is
|
||||||
|
created. This is done only when ``<LANG>`` is ``C`` or ``CXX``.
|
|
@ -667,10 +667,23 @@ cmMakefileTargetGenerator
|
||||||
{
|
{
|
||||||
std::string const iwyu_prop = lang + "_INCLUDE_WHAT_YOU_USE";
|
std::string const iwyu_prop = lang + "_INCLUDE_WHAT_YOU_USE";
|
||||||
const char *iwyu = this->GeneratorTarget->GetProperty(iwyu_prop);
|
const char *iwyu = this->GeneratorTarget->GetProperty(iwyu_prop);
|
||||||
if (iwyu && *iwyu)
|
std::string const tidy_prop = lang + "_CLANG_TIDY";
|
||||||
|
const char *tidy = this->GeneratorTarget->GetProperty(tidy_prop);
|
||||||
|
if ((iwyu && *iwyu) || (tidy && *tidy))
|
||||||
{
|
{
|
||||||
std::string run_iwyu = "$(CMAKE_COMMAND) -E __run_iwyu --iwyu=";
|
std::string run_iwyu = "$(CMAKE_COMMAND) -E __run_iwyu";
|
||||||
run_iwyu += this->LocalGenerator->EscapeForShell(iwyu);
|
if (iwyu && *iwyu)
|
||||||
|
{
|
||||||
|
run_iwyu += " --iwyu=";
|
||||||
|
run_iwyu += this->LocalGenerator->EscapeForShell(iwyu);
|
||||||
|
}
|
||||||
|
if (tidy && *tidy)
|
||||||
|
{
|
||||||
|
run_iwyu += " --tidy=";
|
||||||
|
run_iwyu += this->LocalGenerator->EscapeForShell(tidy);
|
||||||
|
run_iwyu += " --source=";
|
||||||
|
run_iwyu += sourceFile;
|
||||||
|
}
|
||||||
run_iwyu += " -- ";
|
run_iwyu += " -- ";
|
||||||
compileCommands.front().insert(0, run_iwyu);
|
compileCommands.front().insert(0, run_iwyu);
|
||||||
}
|
}
|
||||||
|
|
|
@ -419,13 +419,25 @@ cmNinjaTargetGenerator
|
||||||
{
|
{
|
||||||
std::string const iwyu_prop = lang + "_INCLUDE_WHAT_YOU_USE";
|
std::string const iwyu_prop = lang + "_INCLUDE_WHAT_YOU_USE";
|
||||||
const char *iwyu = this->GeneratorTarget->GetProperty(iwyu_prop);
|
const char *iwyu = this->GeneratorTarget->GetProperty(iwyu_prop);
|
||||||
if (iwyu && *iwyu)
|
std::string const tidy_prop = lang + "_CLANG_TIDY";
|
||||||
|
const char *tidy = this->GeneratorTarget->GetProperty(tidy_prop);
|
||||||
|
if ((iwyu && *iwyu) || (tidy && *tidy))
|
||||||
{
|
{
|
||||||
std::string run_iwyu =
|
std::string run_iwyu =
|
||||||
this->GetLocalGenerator()->ConvertToOutputFormat(
|
this->GetLocalGenerator()->ConvertToOutputFormat(
|
||||||
cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL);
|
cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL);
|
||||||
run_iwyu += " -E __run_iwyu --iwyu=";
|
run_iwyu += " -E __run_iwyu";
|
||||||
run_iwyu += this->GetLocalGenerator()->EscapeForShell(iwyu);
|
if (iwyu && *iwyu)
|
||||||
|
{
|
||||||
|
run_iwyu += " --iwyu=";
|
||||||
|
run_iwyu += this->GetLocalGenerator()->EscapeForShell(iwyu);
|
||||||
|
}
|
||||||
|
if (tidy && *tidy)
|
||||||
|
{
|
||||||
|
run_iwyu += " --tidy=";
|
||||||
|
run_iwyu += this->GetLocalGenerator()->EscapeForShell(tidy);
|
||||||
|
run_iwyu += " --source=$in";
|
||||||
|
}
|
||||||
run_iwyu += " -- ";
|
run_iwyu += " -- ";
|
||||||
compileCmds.front().insert(0, run_iwyu);
|
compileCmds.front().insert(0, run_iwyu);
|
||||||
}
|
}
|
||||||
|
|
|
@ -142,11 +142,13 @@ void cmTarget::SetMakefile(cmMakefile* mf)
|
||||||
this->SetPropertyDefault("MACOSX_BUNDLE", 0);
|
this->SetPropertyDefault("MACOSX_BUNDLE", 0);
|
||||||
this->SetPropertyDefault("MACOSX_RPATH", 0);
|
this->SetPropertyDefault("MACOSX_RPATH", 0);
|
||||||
this->SetPropertyDefault("NO_SYSTEM_FROM_IMPORTED", 0);
|
this->SetPropertyDefault("NO_SYSTEM_FROM_IMPORTED", 0);
|
||||||
|
this->SetPropertyDefault("C_CLANG_TIDY", 0);
|
||||||
this->SetPropertyDefault("C_COMPILER_LAUNCHER", 0);
|
this->SetPropertyDefault("C_COMPILER_LAUNCHER", 0);
|
||||||
this->SetPropertyDefault("C_INCLUDE_WHAT_YOU_USE", 0);
|
this->SetPropertyDefault("C_INCLUDE_WHAT_YOU_USE", 0);
|
||||||
this->SetPropertyDefault("C_STANDARD", 0);
|
this->SetPropertyDefault("C_STANDARD", 0);
|
||||||
this->SetPropertyDefault("C_STANDARD_REQUIRED", 0);
|
this->SetPropertyDefault("C_STANDARD_REQUIRED", 0);
|
||||||
this->SetPropertyDefault("C_EXTENSIONS", 0);
|
this->SetPropertyDefault("C_EXTENSIONS", 0);
|
||||||
|
this->SetPropertyDefault("CXX_CLANG_TIDY", 0);
|
||||||
this->SetPropertyDefault("CXX_COMPILER_LAUNCHER", 0);
|
this->SetPropertyDefault("CXX_COMPILER_LAUNCHER", 0);
|
||||||
this->SetPropertyDefault("CXX_INCLUDE_WHAT_YOU_USE", 0);
|
this->SetPropertyDefault("CXX_INCLUDE_WHAT_YOU_USE", 0);
|
||||||
this->SetPropertyDefault("CXX_STANDARD", 0);
|
this->SetPropertyDefault("CXX_STANDARD", 0);
|
||||||
|
|
|
@ -297,12 +297,14 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
|
||||||
if (args.size() < 3)
|
if (args.size() < 3)
|
||||||
{
|
{
|
||||||
std::cerr << "__run_iwyu Usage: -E __run_iwyu [--iwyu=/path/iwyu]"
|
std::cerr << "__run_iwyu Usage: -E __run_iwyu [--iwyu=/path/iwyu]"
|
||||||
" -- compile command\n";
|
" [--tidy=/path/tidy] -- compile command\n";
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
bool doing_options = true;
|
bool doing_options = true;
|
||||||
std::vector<std::string> orig_cmd;
|
std::vector<std::string> orig_cmd;
|
||||||
std::string iwyu;
|
std::string iwyu;
|
||||||
|
std::string tidy;
|
||||||
|
std::string sourceFile;
|
||||||
for (std::string::size_type cc = 2; cc < args.size(); cc ++)
|
for (std::string::size_type cc = 2; cc < args.size(); cc ++)
|
||||||
{
|
{
|
||||||
std::string const& arg = args[cc];
|
std::string const& arg = args[cc];
|
||||||
|
@ -314,6 +316,14 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
|
||||||
{
|
{
|
||||||
iwyu = arg.substr(7);
|
iwyu = arg.substr(7);
|
||||||
}
|
}
|
||||||
|
else if (doing_options && cmHasLiteralPrefix(arg, "--tidy="))
|
||||||
|
{
|
||||||
|
tidy = arg.substr(7);
|
||||||
|
}
|
||||||
|
else if (doing_options && cmHasLiteralPrefix(arg, "--source="))
|
||||||
|
{
|
||||||
|
sourceFile = arg.substr(9);
|
||||||
|
}
|
||||||
else if (doing_options)
|
else if (doing_options)
|
||||||
{
|
{
|
||||||
std::cerr << "__run_iwyu given unknown argument: " << arg << "\n";
|
std::cerr << "__run_iwyu given unknown argument: " << arg << "\n";
|
||||||
|
@ -324,9 +334,14 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
|
||||||
orig_cmd.push_back(arg);
|
orig_cmd.push_back(arg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (iwyu.empty())
|
if (tidy.empty() && iwyu.empty())
|
||||||
{
|
{
|
||||||
std::cerr << "__run_iwyu missing --iwyu=\n";
|
std::cerr << "__run_iwyu missing --tidy= or --iwyu=\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (!tidy.empty() && sourceFile.empty())
|
||||||
|
{
|
||||||
|
std::cerr << "__run_iwyu --tidy= requires --source=\n";
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (orig_cmd.empty())
|
if (orig_cmd.empty())
|
||||||
|
@ -335,29 +350,52 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct the iwyu command line by taking what was given
|
|
||||||
// and adding all the arguments we give to the compiler.
|
|
||||||
std::vector<std::string> iwyu_cmd;
|
|
||||||
cmSystemTools::ExpandListArgument(iwyu, iwyu_cmd, true);
|
|
||||||
iwyu_cmd.insert(iwyu_cmd.end(), orig_cmd.begin()+1, orig_cmd.end());
|
|
||||||
|
|
||||||
// Run the iwyu command line. Capture its stderr and hide its stdout.
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
std::string stdErr;
|
|
||||||
if(!cmSystemTools::RunSingleCommand(iwyu_cmd, 0, &stdErr, &ret,
|
if (!iwyu.empty())
|
||||||
0, cmSystemTools::OUTPUT_NONE))
|
|
||||||
{
|
{
|
||||||
std::cerr << "Error running '" << iwyu_cmd[0] << "': "
|
// Construct the iwyu command line by taking what was given
|
||||||
<< stdErr << "\n";
|
// and adding all the arguments we give to the compiler.
|
||||||
return 1;
|
std::vector<std::string> iwyu_cmd;
|
||||||
|
cmSystemTools::ExpandListArgument(iwyu, iwyu_cmd, true);
|
||||||
|
iwyu_cmd.insert(iwyu_cmd.end(), orig_cmd.begin()+1, orig_cmd.end());
|
||||||
|
|
||||||
|
// Run the iwyu command line. Capture its stderr and hide its stdout.
|
||||||
|
std::string stdErr;
|
||||||
|
if(!cmSystemTools::RunSingleCommand(iwyu_cmd, 0, &stdErr, &ret,
|
||||||
|
0, cmSystemTools::OUTPUT_NONE))
|
||||||
|
{
|
||||||
|
std::cerr << "Error running '" << iwyu_cmd[0] << "': "
|
||||||
|
<< stdErr << "\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warn if iwyu reported anything.
|
||||||
|
if(stdErr.find("should remove these lines:") != stdErr.npos
|
||||||
|
|| stdErr.find("should add these lines:") != stdErr.npos)
|
||||||
|
{
|
||||||
|
std::cerr << "Warning: include-what-you-use reported diagnostics:\n"
|
||||||
|
<< stdErr << "\n";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Warn if iwyu reported anything.
|
if (!tidy.empty())
|
||||||
if(stdErr.find("should remove these lines:") != stdErr.npos
|
|
||||||
|| stdErr.find("should add these lines:") != stdErr.npos)
|
|
||||||
{
|
{
|
||||||
std::cerr << "Warning: include-what-you-use reported diagnostics:\n"
|
// Construct the clang-tidy command line by taking what was given
|
||||||
<< stdErr << "\n";
|
// and adding all the arguments we give to the compiler.
|
||||||
|
std::vector<std::string> tidy_cmd;
|
||||||
|
cmSystemTools::ExpandListArgument(tidy, tidy_cmd, true);
|
||||||
|
tidy_cmd.push_back(sourceFile);
|
||||||
|
tidy_cmd.push_back("--");
|
||||||
|
tidy_cmd.insert(tidy_cmd.end(), orig_cmd.begin()+1, orig_cmd.end());
|
||||||
|
|
||||||
|
// Run the tidy command line.
|
||||||
|
if(!cmSystemTools::RunSingleCommand(tidy_cmd, 0, 0, &ret, 0,
|
||||||
|
cmSystemTools::OUTPUT_PASSTHROUGH))
|
||||||
|
{
|
||||||
|
std::cerr << "Error running '" << tidy_cmd[0] << "'\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now run the real compiler command and return its result value.
|
// Now run the real compiler command and return its result value.
|
||||||
|
|
|
@ -301,7 +301,9 @@ if(CMAKE_OSX_ARCHITECTURES AND XCODE AND NOT "${XCODE_VERSION}" MATCHES "^[^12]"
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if("${CMAKE_GENERATOR}" MATCHES "Make|Ninja")
|
if("${CMAKE_GENERATOR}" MATCHES "Make|Ninja")
|
||||||
|
add_executable(pseudo_tidy pseudo_tidy.c)
|
||||||
add_executable(pseudo_iwyu pseudo_iwyu.c)
|
add_executable(pseudo_iwyu pseudo_iwyu.c)
|
||||||
|
add_RunCMake_test(ClangTidy -DPSEUDO_TIDY=$<TARGET_FILE:pseudo_tidy>)
|
||||||
add_RunCMake_test(IncludeWhatYouUse -DPSEUDO_IWYU=$<TARGET_FILE:pseudo_iwyu>)
|
add_RunCMake_test(IncludeWhatYouUse -DPSEUDO_IWYU=$<TARGET_FILE:pseudo_iwyu>)
|
||||||
add_RunCMake_test(CompilerLauncher)
|
add_RunCMake_test(CompilerLauncher)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Tests[/\]RunCMake[/\]ClangTidy[/\]main\.c:0:0: warning: message \[checker\]
|
|
@ -0,0 +1 @@
|
||||||
|
Tests[/\]RunCMake[/\]ClangTidy[/\]main\.c:0:0: warning: message \[checker\]
|
|
@ -0,0 +1,3 @@
|
||||||
|
set(CTEST_USE_LAUNCHERS 1)
|
||||||
|
include(CTestUseLaunchers)
|
||||||
|
include(C.cmake)
|
|
@ -0,0 +1,3 @@
|
||||||
|
enable_language(C)
|
||||||
|
set(CMAKE_C_CLANG_TIDY "${PSEUDO_TIDY}" -some -args)
|
||||||
|
add_executable(main main.c)
|
|
@ -0,0 +1,3 @@
|
||||||
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
project(${RunCMake_TEST} NONE)
|
||||||
|
include(${RunCMake_TEST}.cmake)
|
|
@ -0,0 +1 @@
|
||||||
|
Tests[/\]RunCMake[/\]ClangTidy[/\]main\.cxx:0:0: warning: message \[checker\]
|
|
@ -0,0 +1 @@
|
||||||
|
Tests[/\]RunCMake[/\]ClangTidy[/\]main\.cxx:0:0: warning: message \[checker\]
|
|
@ -0,0 +1,3 @@
|
||||||
|
set(CTEST_USE_LAUNCHERS 1)
|
||||||
|
include(CTestUseLaunchers)
|
||||||
|
include(CXX.cmake)
|
|
@ -0,0 +1,3 @@
|
||||||
|
enable_language(CXX)
|
||||||
|
set(CMAKE_CXX_CLANG_TIDY "${PSEUDO_TIDY}" -some -args)
|
||||||
|
add_executable(main main.cxx)
|
|
@ -0,0 +1,22 @@
|
||||||
|
include(RunCMake)
|
||||||
|
|
||||||
|
set(RunCMake_TEST_OPTIONS "-DPSEUDO_TIDY=${PSEUDO_TIDY}")
|
||||||
|
|
||||||
|
function(run_tidy lang)
|
||||||
|
# Use a single build tree for tests without cleaning.
|
||||||
|
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${lang}-build)
|
||||||
|
set(RunCMake_TEST_NO_CLEAN 1)
|
||||||
|
file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
|
||||||
|
file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
|
||||||
|
run_cmake(${lang})
|
||||||
|
|
||||||
|
set(RunCMake_TEST_OUTPUT_MERGE 1)
|
||||||
|
run_cmake_command(${lang}-Build ${CMAKE_COMMAND} --build .)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
run_tidy(C)
|
||||||
|
run_tidy(CXX)
|
||||||
|
if (NOT RunCMake_GENERATOR STREQUAL "Watcom WMake")
|
||||||
|
run_tidy(C-launch)
|
||||||
|
run_tidy(CXX-launch)
|
||||||
|
endif()
|
|
@ -0,0 +1 @@
|
||||||
|
int main(void) { return 0; }
|
|
@ -0,0 +1 @@
|
||||||
|
int main() { return 0; }
|
|
@ -1 +1 @@
|
||||||
^__run_iwyu missing --iwyu=$
|
^__run_iwyu missing --tidy= or --iwyu=$
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 1; i < argc; ++i)
|
||||||
|
{
|
||||||
|
if (argv[i][0] != '-')
|
||||||
|
{
|
||||||
|
fprintf(stdout, "%s:0:0: warning: message [checker]\n", argv[i]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fprintf(stderr, "1 warning generated.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue