Я пытаюсь создать инструмент с clang, и мне было интересно, можно ли вставить включаемый файл из памяти в препроцессор CompilerInstance.
Моя цель - добавить #include <my_globals.hpp> в мои файлы и динамически включать этот файл с соответствующим содержанием. Итак, у меня есть ASTFrontendAction вот такой:

class MyFrontendAction : public ASTFrontendAction
{
    virtual bool BeginInvocation(CompilerInstance &ci) override{
        auto buffer = llvm::MemoryBuffer::getMemBufferCopy(...);
        ci.createFileManager();
        ci.createSourceManager(ci.getFileManager());
        ci.createPreprocessor(clang::TU_Complete);
        auto& pp = ci.getPreprocessor();
        auto& preprocessorOpts = pp.getPreprocessorOpts();
        preprocessorOpts.clearRemappedFiles();
        preprocessorOpts.addRemappedFile("my_globals.hpp", buffer.release());
        // this seams not to work
        auto& hsi = pp.getHeaderSearchInfo();
        auto& headerSearchOptions = hsi.getHeaderSearchOpts();
        headerSearchOptions.Verbose = true; // this option is used during job

    }
    std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance& ci, StringRef file) override{/* do my parsing */}

};

Синтаксический анализ работает до тех пор, пока я не включаю свой заголовочный файл. Если я это сделаю, то получу my_globals.hpp file not found.
Таким образом, addRemappedFile не делает этот файл видимым для препроцессора. Я мог бы добавить путь поиска, но как я могу указать, что у этого файла нет пути?
Может ли кто-нибудь дать мне подсказку, как я могу это решить.

2
mkaes 6 Июл 2017 в 11:31
Может быть, это подскажет вам какие-нибудь идеи? github.com/burnflare/libclang-experiments Кажется, есть довольно много описания того, как сделать что-то подобное в описании на этой странице.
 – 
xaxxon
7 Июл 2017 в 08:35
Есть ли разница, если вы вызываете ci.getPreprocessorOpts () вместо pp.getPreprocessorOpts ()?
 – 
jvstech
8 Июл 2017 в 03:51
@jvstech: Похоже, без разницы. Если я создам PP после этого, я получаю несколько утверждений, но в конце концов результат будет таким же.
 – 
mkaes
10 Июл 2017 в 12:44
Я сейчас активно работаю над этой же проблемой. Похоже, что ответ вероятно кроется в ci.getHeaderSearchOpts().AddVFSOverlayFile(). Вам нужно будет создать clang::vfs::OverlayFileSystem и clang::vfs::InMemoryFileSystem, позвонить overlayFs->pushOverlay(memoryFS), а затем позвонить memoryFs->addFile("my_globals.hpp", llvm::MemoryBuffer::getMemBufferCopy(myGlobalsCode.c_str()). Однако я протестирую это, прежде чем отправлять его в качестве ответа.
 – 
jvstech
10 Июл 2017 в 13:10
1
@jvstech: Я решил проблему с помощью собственной реализации FileSystem. Поскольку это слишком долго для комментария, я ответил на свой вопрос. Возможно, это поможет и для вашей проблемы.
 – 
mkaes
11 Июл 2017 в 16:41

1 ответ

Лучший ответ

Я отвечу на свой вопрос, может быть, это будет полезно. Хотя PPCallbacks вызываются всякий раз, когда препроцессор касается файла, я не нашел способа изменить содержимое. Итак, мое решение - предоставить свой собственный FileSystem

class MyFs : public FileSystem{
    ... openFileForRead(const Twine& Path) overwrite
    {
    // in here I create my own File that will contain the data
    // all other functions and when the path is not what I expect I forward it to a FileSystrem
    }
};
class MyFrontendAction : public ASTFrontendAction
{
    virtual bool BeginInvocation(CompilerInstance &ci) override{
        ci.createFileManager(); // now I have a default FS
        llvm::IntrusiveRefCntPtr<vfs::FileSystem> fs(new MyFs(ci.getFileManager().getVirtualFileSystem()));
        ci.setVirtualFileSystem(fs);
        ci.setFileManager(new clang::FileManager(clang::FileSystemOptions{}, fs));
        auto& fm = ci.getFileManager();
        ci.createSourceManager(fm);
        return true;
    }
    std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance& ci, StringRef file) override{/* do my parsing */}

};
3
mkaes 11 Июл 2017 в 16:40
Извините за задержку с ответом; спасибо за опыт обучения. :)
 – 
jvstech
25 Июл 2017 в 16:21