fatal error: 'stddef.h' file not found when using clang-llvm ASTMatcher
fatal error: 'stddef.h' file not found when using clang-llvm ASTMatcher
我刚开始使用 ASTMatcher 并遵循教程中的代码 - https://github.com/peter-can-talk/cppnow-2017。在这里,工具 clang-variables 可以是 运行 使用以下命令:
cd code/clang-variables
docker run -it -v $PWD:/home clang
root@5196c095092d:/home# ./clang-variables test.cpp -- -std=c++14
而不是 test.cpp 文件,如果我使用另一个源文件,则会收到以下错误:
fatal error: 'stddef.h' file not found
#include <stddef.h>
^~~~~~~~~~
我知道我的源文件有这些需要包含的头文件。我尝试将它们包含在 Makefile 中,但错误仍然存在:
clang-variables: $(TARGET).cpp
$(CXX) $(HEADERS) $(LDFLAGS) $(CXXFLAGS) $(TARGET).cpp $(LIBS) -o $(TARGET) -I$(START_DIR)/source -I$(HOME_ROOT)/extern/include
编译时没有错误。所以我想知道,是否可以将包含文件作为 ASTMatcher 的参数提及?请在下面找到代码:
// Clang includes
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/Type.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendAction.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Tooling.h"
// LLVM includes
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/raw_ostream.h"
// Standard includes
#include <memory>
#include <string>
#include <vector>
namespace Mutator {
/// Callback class for clang-variable matches.
class MatchHandler : public clang::ast_matchers::MatchFinder::MatchCallback {
public:
using MatchResult = clang::ast_matchers::MatchFinder::MatchResult;
/// Handles the matched variable.
///
/// Checks if the name of the matched variable is either empty or prefixed
/// with `clang_` else emits a diagnostic and FixItHint.
void run(const MatchResult& Result) {
const clang::VarDecl* Variable =
Result.Nodes.getNodeAs<clang::VarDecl>("clang");
const llvm::StringRef Name = Variable->getName();
if (Name.empty() || Name.startswith("clang_")) return;
clang::DiagnosticsEngine& Engine = Result.Context->getDiagnostics();
const unsigned ID =
Engine.getCustomDiagID(clang::DiagnosticsEngine::Warning,
"found mutating variable");
/// Hint to the user to prefix the variable with 'clang_'.
const clang::FixItHint FixIt =
clang::FixItHint::CreateInsertion(Variable->getLocation(), "precision & accuracy mutation");
Engine.Report(Variable->getLocation(), ID).AddFixItHint(FixIt);
}
}; // namespace Mutator
/// Dispatches the ASTMatcher.
class Consumer : public clang::ASTConsumer {
public:
/// Creates the matcher for clang variables and dispatches it on the TU.
void HandleTranslationUnit(clang::ASTContext& Context) override {
using namespace clang::ast_matchers; // NOLINT(build/namespaces)
const auto Matcher = declaratorDecl(
isExpansionInMainFile(),
hasType(asString("int"))
).bind("clang");
/*
// clang-format off
const auto Matcher = varDecl(
isExpansionInMainFile(),
hasType(isConstQualified()), // const
hasInitializer(
hasType(cxxRecordDecl(
isLambda(), // lambda
has(functionTemplateDecl( // auto
has(cxxMethodDecl(
isNoThrow(), // noexcept
hasBody(compoundStmt(hasDescendant(gotoStmt()))) // goto
)))))))).bind("clang");
// clang-format on
*/
MatchHandler Handler;
MatchFinder MatchFinder;
MatchFinder.addMatcher(Matcher, &Handler);
MatchFinder.matchAST(Context);
}
};
/// Creates an `ASTConsumer` and logs begin and end of file processing.
class Action : public clang::ASTFrontendAction {
public:
using ASTConsumerPointer = std::unique_ptr<clang::ASTConsumer>;
ASTConsumerPointer CreateASTConsumer(clang::CompilerInstance& Compiler,
llvm::StringRef) override {
return std::make_unique<Consumer>();
}
bool BeginSourceFileAction(clang::CompilerInstance& Compiler,
llvm::StringRef Filename) override {
llvm::errs() << "Processing " << Filename << "\n\n";
return true;
}
void EndSourceFileAction() override {
llvm::errs() << "\nFinished processing file ...\n";
}
};
} // namespace Mutator
namespace {
llvm::cl::OptionCategory ToolCategory("clang-variables options");
llvm::cl::extrahelp MoreHelp(R"(
Finds all Const Lambdas, that take an Auto parameter, are declared Noexcept
and have a Goto statement inside, e.g.:
const auto lambda = [] (auto) noexcept {
bool done = true;
flip: done = !done;
if (!done) goto flip;
}
)");
llvm::cl::extrahelp
CommonHelp(clang::tooling::CommonOptionsParser::HelpMessage);
} // namespace
auto main(int argc, const char* argv[]) -> int {
using namespace clang::tooling;
CommonOptionsParser OptionsParser(argc, argv, ToolCategory);
ClangTool Tool(OptionsParser.getCompilations(),
OptionsParser.getSourcePathList());
const auto Action = newFrontendActionFactory<Mutator::Action>();
return Tool.run(Action.get());
}
感谢任何帮助。
Clang 工具实例化编译器 object 以生成 AST。与从分发版安装的编译器(在构建项目时调用)不同,此编译器 object 未配置 header 路径信息。
有(至少)两种方法可以添加该信息:使用标准 header 路径配置编译器,或者将路径添加到编译数据库。
首先,您可以使用 ClangTool::appendArgumentsAdjuster()
方法以编程方式添加路径。这是 CoARCT (https://github.com/lanl/CoARCT) 中 apps/FuncLister.cc 的示例:
ClangTool tool(OptionsParser.getCompilations(),
OptionsParser.getSourcePathList());
// add header search paths to compiler
ArgumentsAdjuster ardj1 =
getInsertArgumentAdjuster(corct::clang_inc_dir1.c_str());
ArgumentsAdjuster ardj2 =
getInsertArgumentAdjuster(corct::clang_inc_dir2.c_str());
tool.appendArgumentsAdjuster(ardj1);
tool.appendArgumentsAdjuster(ardj2);
if(verbose_compiler){
ArgumentsAdjuster ardj3 = getInsertArgumentAdjuster("-v");
tool.appendArgumentsAdjuster(ardj3);
}
CoARCT 分几步定义包含目录:首先,顶层 CMakeLists.txt 猜测目录的位置,并将该信息放入宏中;其次,lib/utilities.h 将宏以编译器标志的形式放入 clang_inc_dir1/2
字符串中(即 clang_inc_dir1="-I/path1/to/headers"
);然后像 FuncLister.cc 这样的客户使用这些作为 appendArgumentsAdjuster() 的参数。
添加编译器搜索路径的第二种方法是更改编译数据库中的编译器命令。如果您使用的是 CMake,请将 set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE)
添加到顶层 CMakeLists.txt。这应该会在构建目录中生成一个名为 compile_commands.json 的编译数据库文件。每个源文件都有一个条目;该条目将包括
"command":"compiler command line here"
您可以将 -I/path/to/headers
添加到您想要 运行 您的工具的任何文件的编译命令中。然后,您可以使用类似
的方式调用该工具
clang-variables test.cpp -p /path/to/compile_commands.json
如果您的项目没有使用 CMake,数据库文件的结构描述如下:https://clang.llvm.org/docs/JSONCompilationDatabase.html.
我刚开始使用 ASTMatcher 并遵循教程中的代码 - https://github.com/peter-can-talk/cppnow-2017。在这里,工具 clang-variables 可以是 运行 使用以下命令:
cd code/clang-variables
docker run -it -v $PWD:/home clang
root@5196c095092d:/home# ./clang-variables test.cpp -- -std=c++14
而不是 test.cpp 文件,如果我使用另一个源文件,则会收到以下错误:
fatal error: 'stddef.h' file not found
#include <stddef.h>
^~~~~~~~~~
我知道我的源文件有这些需要包含的头文件。我尝试将它们包含在 Makefile 中,但错误仍然存在:
clang-variables: $(TARGET).cpp
$(CXX) $(HEADERS) $(LDFLAGS) $(CXXFLAGS) $(TARGET).cpp $(LIBS) -o $(TARGET) -I$(START_DIR)/source -I$(HOME_ROOT)/extern/include
编译时没有错误。所以我想知道,是否可以将包含文件作为 ASTMatcher 的参数提及?请在下面找到代码:
// Clang includes
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/Type.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendAction.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Tooling.h"
// LLVM includes
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/raw_ostream.h"
// Standard includes
#include <memory>
#include <string>
#include <vector>
namespace Mutator {
/// Callback class for clang-variable matches.
class MatchHandler : public clang::ast_matchers::MatchFinder::MatchCallback {
public:
using MatchResult = clang::ast_matchers::MatchFinder::MatchResult;
/// Handles the matched variable.
///
/// Checks if the name of the matched variable is either empty or prefixed
/// with `clang_` else emits a diagnostic and FixItHint.
void run(const MatchResult& Result) {
const clang::VarDecl* Variable =
Result.Nodes.getNodeAs<clang::VarDecl>("clang");
const llvm::StringRef Name = Variable->getName();
if (Name.empty() || Name.startswith("clang_")) return;
clang::DiagnosticsEngine& Engine = Result.Context->getDiagnostics();
const unsigned ID =
Engine.getCustomDiagID(clang::DiagnosticsEngine::Warning,
"found mutating variable");
/// Hint to the user to prefix the variable with 'clang_'.
const clang::FixItHint FixIt =
clang::FixItHint::CreateInsertion(Variable->getLocation(), "precision & accuracy mutation");
Engine.Report(Variable->getLocation(), ID).AddFixItHint(FixIt);
}
}; // namespace Mutator
/// Dispatches the ASTMatcher.
class Consumer : public clang::ASTConsumer {
public:
/// Creates the matcher for clang variables and dispatches it on the TU.
void HandleTranslationUnit(clang::ASTContext& Context) override {
using namespace clang::ast_matchers; // NOLINT(build/namespaces)
const auto Matcher = declaratorDecl(
isExpansionInMainFile(),
hasType(asString("int"))
).bind("clang");
/*
// clang-format off
const auto Matcher = varDecl(
isExpansionInMainFile(),
hasType(isConstQualified()), // const
hasInitializer(
hasType(cxxRecordDecl(
isLambda(), // lambda
has(functionTemplateDecl( // auto
has(cxxMethodDecl(
isNoThrow(), // noexcept
hasBody(compoundStmt(hasDescendant(gotoStmt()))) // goto
)))))))).bind("clang");
// clang-format on
*/
MatchHandler Handler;
MatchFinder MatchFinder;
MatchFinder.addMatcher(Matcher, &Handler);
MatchFinder.matchAST(Context);
}
};
/// Creates an `ASTConsumer` and logs begin and end of file processing.
class Action : public clang::ASTFrontendAction {
public:
using ASTConsumerPointer = std::unique_ptr<clang::ASTConsumer>;
ASTConsumerPointer CreateASTConsumer(clang::CompilerInstance& Compiler,
llvm::StringRef) override {
return std::make_unique<Consumer>();
}
bool BeginSourceFileAction(clang::CompilerInstance& Compiler,
llvm::StringRef Filename) override {
llvm::errs() << "Processing " << Filename << "\n\n";
return true;
}
void EndSourceFileAction() override {
llvm::errs() << "\nFinished processing file ...\n";
}
};
} // namespace Mutator
namespace {
llvm::cl::OptionCategory ToolCategory("clang-variables options");
llvm::cl::extrahelp MoreHelp(R"(
Finds all Const Lambdas, that take an Auto parameter, are declared Noexcept
and have a Goto statement inside, e.g.:
const auto lambda = [] (auto) noexcept {
bool done = true;
flip: done = !done;
if (!done) goto flip;
}
)");
llvm::cl::extrahelp
CommonHelp(clang::tooling::CommonOptionsParser::HelpMessage);
} // namespace
auto main(int argc, const char* argv[]) -> int {
using namespace clang::tooling;
CommonOptionsParser OptionsParser(argc, argv, ToolCategory);
ClangTool Tool(OptionsParser.getCompilations(),
OptionsParser.getSourcePathList());
const auto Action = newFrontendActionFactory<Mutator::Action>();
return Tool.run(Action.get());
}
感谢任何帮助。
Clang 工具实例化编译器 object 以生成 AST。与从分发版安装的编译器(在构建项目时调用)不同,此编译器 object 未配置 header 路径信息。
有(至少)两种方法可以添加该信息:使用标准 header 路径配置编译器,或者将路径添加到编译数据库。
首先,您可以使用 ClangTool::appendArgumentsAdjuster()
方法以编程方式添加路径。这是 CoARCT (https://github.com/lanl/CoARCT) 中 apps/FuncLister.cc 的示例:
ClangTool tool(OptionsParser.getCompilations(),
OptionsParser.getSourcePathList());
// add header search paths to compiler
ArgumentsAdjuster ardj1 =
getInsertArgumentAdjuster(corct::clang_inc_dir1.c_str());
ArgumentsAdjuster ardj2 =
getInsertArgumentAdjuster(corct::clang_inc_dir2.c_str());
tool.appendArgumentsAdjuster(ardj1);
tool.appendArgumentsAdjuster(ardj2);
if(verbose_compiler){
ArgumentsAdjuster ardj3 = getInsertArgumentAdjuster("-v");
tool.appendArgumentsAdjuster(ardj3);
}
CoARCT 分几步定义包含目录:首先,顶层 CMakeLists.txt 猜测目录的位置,并将该信息放入宏中;其次,lib/utilities.h 将宏以编译器标志的形式放入 clang_inc_dir1/2
字符串中(即 clang_inc_dir1="-I/path1/to/headers"
);然后像 FuncLister.cc 这样的客户使用这些作为 appendArgumentsAdjuster() 的参数。
添加编译器搜索路径的第二种方法是更改编译数据库中的编译器命令。如果您使用的是 CMake,请将 set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE)
添加到顶层 CMakeLists.txt。这应该会在构建目录中生成一个名为 compile_commands.json 的编译数据库文件。每个源文件都有一个条目;该条目将包括
"command":"compiler command line here"
您可以将 -I/path/to/headers
添加到您想要 运行 您的工具的任何文件的编译命令中。然后,您可以使用类似
clang-variables test.cpp -p /path/to/compile_commands.json
如果您的项目没有使用 CMake,数据库文件的结构描述如下:https://clang.llvm.org/docs/JSONCompilationDatabase.html.