快速编译C ++:clang / libtooling无法为LLVM IR设置Triple

马修·布鲁彻(Matthieu Brucher)

假设我想即时编译C ++字符串:

llvm::LLVMContext context;

std::unique_ptr<clang::CodeGenAction> action = std::make_unique<clang::EmitLLVMOnlyAction>(&context);
clang::tooling::runToolOnCode/*WithArgs*/(action.get(), "int foo(int x){ return ++x;}");

std::unique_ptr<llvm::Module> module = action->takeModule();

不幸的是,当LLVM尝试转换IR时,似乎有一个例外,说明Triple未设置。(https://clang.llvm.org/docs/CrossCompilation.html#target-triple)。

是否可以使用libtoolinglibclang用于此目的?

马修·布鲁彻(Matthieu Brucher)

不幸的是,很难使用这些接口来创建合适的LLVM模块。唯一的方法甚至是创建一个文件并编译该文件,并设置所有包含路径:

首先,有很多包含要添加的内容:

#include <clang/AST/ASTContext.h>
#include <clang/AST/ASTConsumer.h>
#include <clang/Basic/DiagnosticOptions.h>
#include <clang/Basic/Diagnostic.h>
#include <clang/Basic/FileManager.h>
#include <clang/Basic/FileSystemOptions.h>
#include <clang/Basic/LangOptions.h>
#include <clang/Basic/MemoryBufferCache.h>
#include <clang/Basic/SourceManager.h>
#include <clang/Basic/TargetInfo.h>
#include <clang/CodeGen/CodeGenAction.h>
#include <clang/Frontend/CompilerInstance.h>
#include <clang/Frontend/CompilerInvocation.h>
#include <clang/Frontend/TextDiagnosticPrinter.h>
#include <clang/Lex/HeaderSearch.h>
#include <clang/Lex/HeaderSearchOptions.h>
#include <clang/Lex/Preprocessor.h>
#include <clang/Lex/PreprocessorOptions.h>
#include <clang/Parse/ParseAST.h>
#include <clang/Sema/Sema.h>

然后,我们需要围绕编译器实例设置所有引擎:

clang::DiagnosticOptions diagnosticOptions;
std::unique_ptr<clang::TextDiagnosticPrinter> textDiagnosticPrinter =
  std::make_unique<clang::TextDiagnosticPrinter>(llvm::outs(),
                                                 &diagnosticOptions);
llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> diagIDs;

std::unique_ptr<clang::DiagnosticsEngine> diagnosticsEngine =
  std::make_unique<clang::DiagnosticsEngine>(diagIDs, &diagnosticOptions, textDiagnosticPrinter.get());

clang::CompilerInstance compilerInstance;
auto& compilerInvocation = compilerInstance.getInvocation();

在这里,我们可以设置三元组以及所需的语言类型:

std::stringstream ss;
ss << "-triple=" << llvm::sys::getDefaultTargetTriple();
ss << " -x c++"; // to activate C++
ss << " -fcxx-exceptions";
ss << " -std=c++17";

std::istream_iterator<std::string> begin(ss);
std::istream_iterator<std::string> end;
std::istream_iterator<std::string> i = begin;
std::vector<const char*> itemcstrs;
std::vector<std::string> itemstrs;
while (i != end) {
  itemstrs.push_back(*i);
  ++i;
}

for (unsigned idx = 0; idx < itemstrs.size(); idx++) {
  // note: if itemstrs is modified after this, itemcstrs will be full
  // of invalid pointers! Could make copies, but would have to clean up then...
  itemcstrs.push_back(itemstrs[idx].c_str());
}

clang::CompilerInvocation::CreateFromArgs(compilerInvocation, itemcstrs.data(), itemcstrs.data() + itemcstrs.size(),
 *diagnosticsEngine.release());

然后,我们可以检查设置的选项(仅在此处更改选项是不够的)并添加详细信息:

auto* languageOptions = compilerInvocation.getLangOpts();
auto& preprocessorOptions = compilerInvocation.getPreprocessorOpts();
auto& targetOptions = compilerInvocation.getTargetOpts();
auto& frontEndOptions = compilerInvocation.getFrontendOpts();
#ifdef DEBUG
frontEndOptions.ShowStats = true;
#endif
auto& headerSearchOptions = compilerInvocation.getHeaderSearchOpts();

让我们添加所有包含标头路径:

constexpr std::string_view paths[] = {"/usr/include/c++/8",
  "/usr/include/x86_64-linux-gnu/c++/8",
  "/usr/include/c++/8/backward",
  "/usr/include/clang/6.0.0/include",
  "/usr/local/include",
  "/usr/include/x86_64-linux-gnu",
  "/usr/include"};

for(auto path: paths)
{
    headerSearchOptions.AddPath(std::string(path), clang::frontend::IncludeDirGroup::Angled, false, false);
}

#ifdef DEBUG
headerSearchOptions.Verbose = true;
#endif
auto& codeGenOptions = compilerInvocation.getCodeGenOpts();

这里应该有一种设置类似文件的字符串的方式(不使用FrontendInputFile),但是不幸的是,在LLVM 7中,要进行检查以确保它是真实文件...

frontEndOptions.Inputs.clear();
frontEndOptions.Inputs.push_back(clang::FrontendInputFile(filename, clang::InputKind::CXX));

targetOptions.Triple = llvm::sys::getDefaultTargetTriple();
compilerInstance.createDiagnostics(textDiagnosticPrinter.get(), false);

LLVM::Context context;

现在创建代码生成器动作,并使编译器实例执行该动作:

std::unique_ptr<clang::CodeGenAction> action = std::make_unique<clang::EmitLLVMOnlyAction>(&context);

if (!compilerInstance.ExecuteAction(*action))
{
    // Failed to compile, and should display on cout the result of the compilation
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如何使clang编译为llvm IR

Clang-将C标头编译为LLVM IR /位码

无法将自定义生成的 LLVM IR 与 Clang 生成的 IR 链接起来

Clang ++编译,但无法运行

llvm / clang编译错误,内存耗尽

如何为 Android 编译 LLVM/Clang?

LLVM/Clang 是否由 GCC 引导/编译?

在Travis CI上为C ++ 17设置Clang

为什么此clang代码无法使用-std = c ++ 20的clang 10进行编译

CLang ++在LLVM_IR中生成伪变量

使用Clang构建V8并发出LLVM IR

Clang可以通过管道接受LLVM IR或位码吗?

LLVM libc ++无法在Mac OS上与clang 3.3一起编译

clang++ 无法编译 hello world

Clang 错误:无法编译内置函数

在OpenCV上。C ++编译器无法编译简单的测试程序。使用Clang ++

C编译器“ / usr / bin / clang”无法编译简单的测试程序

如何为使用Clang LLVM编译的C ++代码生成图形代码配置文件报告?

如何使用clang -emit-llvm编译和保留“未使用的” C声明

修改由Clang / LLVM编译器执行的优化

Windows中的OpenMP代码的LLVM / Clang 8编译

来自clang / llvm编译器的重复符号错误

clang -Xclang -cc1 -O3 mips.c -emit-llvm,clang错误:-emit-llvm链接时无法使用

是否可以将 Clang libtooling 与其他编译器一起使用?

如何在Visual Studio 2015中使用Clang为Windows编译C ++

使用 ndk arm-linux-androideabi-clang++ 编译器为 android 构建 grpc C++

GCC和Clang无法在C ++ 17中编译std :: hash <std :: nullptr_t>

简单的std :: regex_search()代码无法与Apple clang ++一起编译-std = c ++ 14

C警告(clang编译器)“整数文字太大,无法用有符号整数表示”