Как я могу использовать LibTooling/Clang в Visual Studio?

Я пытаюсь использовать LibTooling для замены имен функций и переменных в файлах C-кода. Поэтому я скачал llvm и, следуя инструкциям, установил его в Windows с помощью GMake и Visual Studio 2015.

Существует множество руководств (например, этот), которым я хотел бы следовать, но все они предполагают, что вы используете Linux/Make, поэтому они предоставляют Makefile, который каким-то образом управляет интеграцией в исходный код llvm.

Я хочу использовать эти примеры в Visual Studio, но я не знаю, с чего начать — могу ли я просто создать новый проект внутри данного (llvn.sln) решения и добавить туда код? Как указать Visual Studio включить исходники clang (как определено в упомянутых мной файлах Makefile)?


person Alex H.    schedule 21.10.2015    source источник


Ответы (3)


Среда: Windows 10 X64, VS2017, CMake 3.9.3 Ссылки: https://clang.llvm.org/get_started.html

Создайте рабочий каталог, например D:\software\LLVM.

Загрузите исходный код LLVM и Clang (версия 6.0.0):

http://releases.llvm.org/6.0.0/llvm-6.0.0.src.tar.xz http://releases.llvm.org/6.0.0/cfe-6.0.0.src.tar.xz

извлеките их в рабочий каталог и переименуйте в llvm и clang (удалите коды версий):

D:\software\LLVM\llvm

D:\software\LLVM\clang

если вы сохраните код версии в имени папки, то позже CMake скажет, что не может найти папку «clang»

создайте выходной каталог сборки в рабочем каталоге, например:

D:\software\LLVM\build-x86

и для x64 (только если вам нужна сборка x64):

D:\software\LLVM\build-x64

попасть в выходной каталог сборки:

cd D:\software\LLVM\build-x86

запустите cmake, для сборки x86:

cmake -DLLVM_ENABLE_PROJECTS=clang -G "Visual Studio 15 2017" -A Win32 -Thost=x64 ..\llvm

для сборки x64:

cmake -DLLVM_ENABLE_PROJECTS=clang -G "Visual Studio 15 2017" -A x64 -Thost=x64 ..\llvm

Примечание. Лучше включать только ту цель, которую должен поддерживать ваш clang, иначе процесс сборки будет очень медленным. Чтобы создавать только те цели, которые поддерживает ваш clang, используйте

-DLLVM_TARGETS_TO_BUILD=target_list

Например:

-DLLVM_TARGETS_TO_BUILD="X86;ARM"

Список всех целей, кажется, находится в:

D:\software\LLVM\llvm\bindings\python\llvm\disassembler.py

они есть:

_targets = ['AArch64', 'ARM', 'Hexagon', 'MSP430', 'Mips', 'NVPTX', 'PowerPC', 'R600', 'Sparc', 'SystemZ', 'X86', 'XCore']

Таким образом, X86, похоже, включает в себя как x86, так и x64.

CMake создаст файл решения VS:

D:\software\LLVM\build-x86\LLVM.sln

откройте его с помощью VS2017, и вам нужно только создать подгруппу «Библиотеки Clang», моя сборка является сборкой отладки по умолчанию.

Теперь ссылка: https://kevinaboos.wordpress.com/2013/07/23/clang-tutorial-part-ii-libtooling-example/, но код на этой странице предназначен для более старой версии LLVM, поэтому он не будет компилироваться.

Вот рабочий код с LLVM6.0.0:

создать консольное приложение C++ в VS2017.

войдите в конфигурацию отладки/x86.

в диалоговом окне свойств проекта для конфигурации отладки/win32,

измените «Отключить определенные предупреждения» на:

4146

измените «Дополнительные каталоги включения» на:

D:\software\LLVM\clang\include;D:\software\LLVM\llvm\include;D:\software\LLVM\build-x86\include;D:\software\LLVM\build-x86\tools\clang\include;%(AdditionalIncludeDirectories)

измените «Дополнительные каталоги библиотек» на:

D:\software\LLVM\build-x86\Debug\lib;%(AdditionalLibraryDirectories)

измените «Дополнительные зависимости» на:

Mincore.lib;clangAnalysis.lib;clangARCMigrate.lib;clangAST.lib;clangASTMatchers.lib;clangBasic.lib;clangCodeGen.lib;clangCrossTU.lib;clangDriver.lib;clangDynamicASTMatchers.lib;clangEdit.lib;clangFormat.lib;clangFrontend.lib;clangFrontendTool.lib;clangHandleCXX.lib;clangIndex.lib;clangLex.lib;clangParse.lib;clangRewrite.lib;clangRewriteFrontend.lib;clangSema.lib;clangSerialization.lib;clangStaticAnalyzerCheckers.lib;clangStaticAnalyzerCore.lib;clangStaticAnalyzerFrontend.lib;clangTooling.lib;clangToolingASTDiff.lib;clangToolingCore.lib;clangToolingRefactor.lib;libclang.lib;LLVMAArch64AsmParser.lib;LLVMAArch64AsmPrinter.lib;LLVMAArch64CodeGen.lib;LLVMAArch64Desc.lib;LLVMAArch64Disassembler.lib;LLVMAArch64Info.lib;LLVMAArch64Utils.lib;LLVMAMDGPUAsmParser.lib;LLVMAMDGPUAsmPrinter.lib;LLVMAMDGPUCodeGen.lib;LLVMAMDGPUDesc.lib;LLVMAMDGPUDisassembler.lib;LLVMAMDGPUInfo.lib;LLVMAMDGPUUtils.lib;LLVMAnalysis.lib;LLVMARMAsmParser.lib;LLVMARMAsmPrinter.lib;LLVMARMCodeGen.lib;LLVMARMDesc.lib;LLVMARMDisassembler.lib;LLVMARMInfo.lib;LLVMARMUtils.lib;LLVMAsmParser.lib;LLVMAsmPrinter.lib;LLVMBinaryFormat.lib;LLVMBitReader.lib;LLVMBitWriter.lib;LLVMBPFAsmParser.lib;LLVMBPFAsmPrinter.lib;LLVMBPFCodeGen.lib;LLVMBPFDesc.lib;LLVMBPFDisassembler.lib;LLVMBPFInfo.lib;LLVMCodeGen.lib;LLVMCore.lib;LLVMDebugInfoCodeView.lib;LLVMDebugInfoMSF.lib;LLVMDemangle.lib;LLVMGlobalISel.lib;LLVMHexagonAsmParser.lib;LLVMHexagonCodeGen.lib;LLVMHexagonDesc.lib;LLVMHexagonDisassembler.lib;LLVMHexagonInfo.lib;LLVMInstCombine.lib;LLVMInstrumentation.lib;LLVMipo.lib;LLVMIRReader.lib;LLVMLanaiAsmParser.lib;LLVMLanaiAsmPrinter.lib;LLVMLanaiCodeGen.lib;LLVMLanaiDesc.lib;LLVMLanaiDisassembler.lib;LLVMLanaiInfo.lib;LLVMLinker.lib;LLVMMC.lib;LLVMMCDisassembler.lib;LLVMMCParser.lib;LLVMMipsAsmParser.lib;LLVMMipsAsmPrinter.lib;LLVMMipsCodeGen.lib;LLVMMipsDesc.lib;LLVMMipsDisassembler.lib;LLVMMipsInfo.lib;LLVMMSP430AsmPrinter.lib;LLVMMSP430CodeGen.lib;LLVMMSP430Desc.lib;LLVMMSP430Info.lib;LLVMNVPTXAsmPrinter.lib;LLVMNVPTXCodeGen.lib;LLVMNVPTXDesc.lib;LLVMNVPTXInfo.lib;LLVMObject.lib;LLVMOption.lib;LLVMPowerPCAsmParser.lib;LLVMPowerPCAsmPrinter.lib;LLVMPowerPCCodeGen.lib;LLVMPowerPCDesc.lib;LLVMPowerPCDisassembler.lib;LLVMPowerPCInfo.lib;LLVMProfileData.lib;LLVMScalarOpts.lib;LLVMSelectionDAG.lib;LLVMSparcAsmParser.lib;LLVMSparcAsmPrinter.lib;LLVMSparcCodeGen.lib;LLVMSparcDesc.lib;LLVMSparcDisassembler.lib;LLVMSparcInfo.lib;LLVMSupport.lib;LLVMSystemZAsmParser.lib;LLVMSystemZAsmPrinter.lib;LLVMSystemZCodeGen.lib;LLVMSystemZDesc.lib;LLVMSystemZDisassembler.lib;LLVMSystemZInfo.lib;LLVMTableGen.lib;LLVMTarget.lib;LLVMTransformUtils.lib;LLVMVectorize.lib;LLVMX86AsmParser.lib;LLVMX86AsmPrinter.lib;LLVMX86CodeGen.lib;LLVMX86Desc.lib;LLVMX86Disassembler.lib;LLVMX86Info.lib;LLVMX86Utils.lib;LLVMXCoreAsmPrinter.lib;LLVMXCoreCodeGen.lib;LLVMXCoreDesc.lib;LLVMXCoreDisassembler.lib;LLVMXCoreInfo.lib;

поскольку я не могу найти информацию о том, какую библиотеку включить, я включаю все библиотеки в D:\software\LLVM\build-x86\Debug\lib, плюс Mincore.lib

Вот код С# для создания ссылок на библиотеки:

static void buildLLVMLibList()
{
    string s = "";
    foreach (string fn in Directory.GetFiles(
        //@"D:\software\LLVM\build-x64\Debug\lib"
        @"D:\software\LLVM\build-x86\Debug\lib"
        , "*.lib"))
    {
        s += new FileInfo(fn).Name + ";";
    }
    return;//break here
}

изменить pch.h на:

#ifndef PCH_H
#define PCH_H

// TODO: add headers that you want to pre-compile here
// Declares clang::SyntaxOnlyAction.
#include "clang/Frontend/FrontendActions.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Tooling.h"
// Declares llvm::cl::extrahelp.
#include "llvm/Support/CommandLine.h"

#include "clang/Driver/Options.h"
#include "clang/AST/AST.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Frontend/ASTConsumers.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Tooling.h"
#include "clang/Rewrite/Core/Rewriter.h"

using namespace std;
using namespace clang;
using namespace clang::driver;
using namespace clang::tooling;
using namespace llvm;

#endif //PCH_H

изменить основной файл cpp на:

#include "pch.h"
#include <iostream>



Rewriter rewriter;
int numFunctions = 0;
llvm::cl::OptionCategory MyToolCategory("my-tool options");

class ExampleVisitor : public RecursiveASTVisitor<ExampleVisitor> {
private:
    ASTContext *astContext; // used for getting additional AST info

public:
    explicit ExampleVisitor(CompilerInstance *CI)
        : astContext(&(CI->getASTContext())) // initialize private members
    {
        rewriter.setSourceMgr(astContext->getSourceManager(),
            astContext->getLangOpts());
    }

    virtual bool VisitFunctionDecl(FunctionDecl *func) {
        numFunctions++;
        string funcName = func->getNameInfo().getName().getAsString();
        if (funcName == "do_math") {
            rewriter.ReplaceText(func->getLocation(), funcName.length(), "add5");
            errs() << "** Rewrote function def: " << funcName << "\n";
        }
        return true;
    }

    virtual bool VisitStmt(Stmt *st) {
        if (ReturnStmt *ret = dyn_cast<ReturnStmt>(st)) {
            rewriter.ReplaceText(ret->getRetValue()->getLocStart(), 6, "val");
            errs() << "** Rewrote ReturnStmt\n";
        }
        if (CallExpr *call = dyn_cast<CallExpr>(st)) {
            rewriter.ReplaceText(call->getLocStart(), 7, "add5");
            errs() << "** Rewrote function call\n";
        }
        return true;
    }
};


class ExampleASTConsumer : public ASTConsumer {
private:
    ExampleVisitor *visitor; // doesn't have to be private

public:
    // override the constructor in order to pass CI
    explicit ExampleASTConsumer(CompilerInstance *CI)
        : visitor(new ExampleVisitor(CI)) // initialize the visitor
    { }

    // override this to call our ExampleVisitor on the entire source file
    virtual void HandleTranslationUnit(ASTContext &Context) {
        /* we can use ASTContext to get the TranslationUnitDecl, which is
             a single Decl that collectively represents the entire source file */
        visitor->TraverseDecl(Context.getTranslationUnitDecl());
    }

};



class ExampleFrontendAction : public ASTFrontendAction {
public:

    void EndSourceFileAction() override {
        llvm::outs() << "END OF FILE ACTION:\n";
        rewriter.getEditBuffer(rewriter.getSourceMgr().getMainFileID()).write(errs());
    }

    virtual std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, StringRef file) {
        return  std::unique_ptr<ASTConsumer>(new ExampleASTConsumer(&CI)); // pass CI pointer to ASTConsumer
    }
};


extern llvm::cl::OptionCategory MyToolCategory;

int main(int argc, const char **argv) {
    // parse the command-line args passed to your code
    CommonOptionsParser op(argc, argv, MyToolCategory);
    // create a new Clang Tool instance (a LibTooling environment)
    ClangTool Tool(op.getCompilations(), op.getSourcePathList());

    // run the Clang Tool, creating a new FrontendAction (explained below)
    int result = Tool.run(newFrontendActionFactory<ExampleFrontendAction>().get());

    errs() << "\nFound " << numFunctions << " functions.\n\n";
    // print out the rewritten source code ("rewriter" is a global var.)

    std::cin.get();
    return result;
}

Затем создайте файл testC++, например:

D:\LLVM\TestSource.cpp

его содержание такое:

void do_math(int *x) {
    *x += 5;
}

int main(void) {
    int result = -1, val = 4;
    do_math(&val);
    return result;
}

затем в свойствах проекта измените «Аргументы команды» на:

"D:\LLVM\TestSource.cpp"

Затем проект будет успешно построен и отлажен.

Для конфигурации отладки/x64 измените свойства проекта на:

включить путь:

D:\software\LLVM\clang\include;D:\software\LLVM\llvm\include;D:\software\LLVM\build-x64\include;D:\software\LLVM\build-x64\tools\clang\include;%(AdditionalIncludeDirectories)

путь к библиотеке:

D:\software\LLVM\build-x64\Debug\lib;%(AdditionalLibraryDirectories)

библиотека (отличается от библиотеки x86):

Mincore.lib;clangAnalysis.lib;clangARCMigrate.lib;clangAST.lib;clangASTMatchers.lib;clangBasic.lib;clangCodeGen.lib;clangCrossTU.lib;clangDriver.lib;clangDynamicASTMatchers.lib;clangEdit.lib;clangFormat.lib;clangFrontend.lib;clangFrontendTool.lib;clangHandleCXX.lib;clangIndex.lib;clangLex.lib;clangParse.lib;clangRewrite.lib;clangRewriteFrontend.lib;clangSema.lib;clangSerialization.lib;clangStaticAnalyzerCheckers.lib;clangStaticAnalyzerCore.lib;clangStaticAnalyzerFrontend.lib;clangTooling.lib;clangToolingASTDiff.lib;clangToolingCore.lib;clangToolingRefactor.lib;gtest.lib;libclang.lib;LLVMAArch64AsmParser.lib;LLVMAArch64AsmPrinter.lib;LLVMAArch64CodeGen.lib;LLVMAArch64Desc.lib;LLVMAArch64Disassembler.lib;LLVMAArch64Info.lib;LLVMAArch64Utils.lib;LLVMAMDGPUAsmParser.lib;LLVMAMDGPUAsmPrinter.lib;LLVMAMDGPUCodeGen.lib;LLVMAMDGPUDesc.lib;LLVMAMDGPUDisassembler.lib;LLVMAMDGPUInfo.lib;LLVMAMDGPUUtils.lib;LLVMAnalysis.lib;LLVMARMAsmParser.lib;LLVMARMAsmPrinter.lib;LLVMARMCodeGen.lib;LLVMARMDesc.lib;LLVMARMDisassembler.lib;LLVMARMInfo.lib;LLVMARMUtils.lib;LLVMAsmParser.lib;LLVMAsmPrinter.lib;LLVMBinaryFormat.lib;LLVMBitReader.lib;LLVMBitWriter.lib;LLVMBPFAsmParser.lib;LLVMBPFAsmPrinter.lib;LLVMBPFCodeGen.lib;LLVMBPFDesc.lib;LLVMBPFDisassembler.lib;LLVMBPFInfo.lib;LLVMCodeGen.lib;LLVMCore.lib;LLVMDebugInfoCodeView.lib;LLVMDebugInfoDWARF.lib;LLVMDebugInfoMSF.lib;LLVMDebugInfoPDB.lib;LLVMDemangle.lib;LLVMGlobalISel.lib;LLVMHexagonAsmParser.lib;LLVMHexagonCodeGen.lib;LLVMHexagonDesc.lib;LLVMHexagonDisassembler.lib;LLVMHexagonInfo.lib;LLVMInstCombine.lib;LLVMInstrumentation.lib;LLVMipo.lib;LLVMIRReader.lib;LLVMLanaiAsmParser.lib;LLVMLanaiAsmPrinter.lib;LLVMLanaiCodeGen.lib;LLVMLanaiDesc.lib;LLVMLanaiDisassembler.lib;LLVMLanaiInfo.lib;LLVMLinker.lib;LLVMMC.lib;LLVMMCDisassembler.lib;LLVMMCParser.lib;LLVMMipsAsmParser.lib;LLVMMipsAsmPrinter.lib;LLVMMipsCodeGen.lib;LLVMMipsDesc.lib;LLVMMipsDisassembler.lib;LLVMMipsInfo.lib;LLVMMSP430AsmPrinter.lib;LLVMMSP430CodeGen.lib;LLVMMSP430Desc.lib;LLVMMSP430Info.lib;LLVMNVPTXAsmPrinter.lib;LLVMNVPTXCodeGen.lib;LLVMNVPTXDesc.lib;LLVMNVPTXInfo.lib;LLVMObject.lib;LLVMOption.lib;LLVMPowerPCAsmParser.lib;LLVMPowerPCAsmPrinter.lib;LLVMPowerPCCodeGen.lib;LLVMPowerPCDesc.lib;LLVMPowerPCDisassembler.lib;LLVMPowerPCInfo.lib;LLVMProfileData.lib;LLVMScalarOpts.lib;LLVMSelectionDAG.lib;LLVMSparcAsmParser.lib;LLVMSparcAsmPrinter.lib;LLVMSparcCodeGen.lib;LLVMSparcDesc.lib;LLVMSparcDisassembler.lib;LLVMSparcInfo.lib;LLVMSupport.lib;LLVMSymbolize.lib;LLVMSystemZAsmParser.lib;LLVMSystemZAsmPrinter.lib;LLVMSystemZCodeGen.lib;LLVMSystemZDesc.lib;LLVMSystemZDisassembler.lib;LLVMSystemZInfo.lib;LLVMTableGen.lib;LLVMTarget.lib;LLVMTransformUtils.lib;LLVMVectorize.lib;LLVMX86AsmParser.lib;LLVMX86AsmPrinter.lib;LLVMX86CodeGen.lib;LLVMX86Desc.lib;LLVMX86Disassembler.lib;LLVMX86Info.lib;LLVMX86Utils.lib;LLVMXCoreAsmPrinter.lib;LLVMXCoreCodeGen.lib;LLVMXCoreDesc.lib;LLVMXCoreDisassembler.lib;LLVMXCoreInfo.lib;

отключить конкретное предупреждение:

4146

аргумент команды:

"D:\LLVM\TestSource.cpp"

Самое главное, вы должны переместить код

rewriter.getEditBuffer(rewriter.getSourceMgr().getMainFileID()).write(errs());

в приведенной выше ссылке из основной функции в ExampleFrontendAction::EndSourceFileAction, иначе будут странные исключения доступа.

person jw_    schedule 25.03.2019
comment
Теперь он говорит об ошибке CMake в CMakeLists.txt: 45 (проект): не удалось запустить команду MSBuild: обходной путь — выполнить команду cmake под собственной подсказкой x86 или x64 VS2017. - person jw_; 16.01.2020

Лучше использовать Cmake для создания файлов проектов Visual Studio, которые затем можно создавать с помощью Visual Studio. В этом руководстве показано, как это делается: https://llvm.org/docs/CMake.html

Часть, которая вам нужна, — это абзац https://llvm.org/docs/CMake.html#usage

person Sylvain David    schedule 04.10.2017

Используя VisualGDB или подобные приложения, можно писать код в Visual Studio и компилировать его на Linux-машине. Это то, что я делаю прямо сейчас. Я установил clang на виртуальную машину Linux, а в моей ОС Windows 7 у меня есть Visual Studio 2010. Он отлично работает.

person M Alipour    schedule 26.08.2016