Использование llvm :: Linker для программного поиска неразрешенных внешних объектов

Я использую clang / llvm для программной компиляции и компоновки битов исходного кода C. Я обнаружил, что компоновщик llvm не сообщает о том, что неразрешенные внешние элементы существуют в модуле, как об ошибке.

У меня есть следующий код (простите за длину, но это действительно минимум):

int CompileAndLink()
{
    llvm::InitializeNativeTarget();

    std::string code = "int UnresolvedFunction();\n"
                       "int main() { return UnresolvedFunction(); }";

    clang::DiagnosticOptions diagnosticOptions;
    clang::TextDiagnosticPrinter tdp( llvm::outs(), diagnosticOptions );    
    llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> diagIDs( new clang::DiagnosticIDs );
    clang::Diagnostic diag( diagIDs, &tdp, false );

    clang::FileSystemOptions    fsOptions;
    clang::FileManager fm( fsOptions ); 

    clang::SourceManager sm( diag, fm );
    clang::HeaderSearch hs( fm );   

    clang::TargetOptions targetOptions;
    targetOptions.Triple = llvm::sys::getHostTriple();
    clang::TargetInfo* ti = clang::TargetInfo::CreateTargetInfo( diag, targetOptions );         

    clang::HeaderSearchOptions  headerSearchOptions;        
    clang::LangOptions langOptions;
    clang::ApplyHeaderSearchOptions( hs, headerSearchOptions, langOptions, ti->getTriple() );

    clang::PreprocessorOptions ppo;
    clang::Preprocessor pp( diag, langOptions, *ti, sm, hs );

    clang::FrontendOptions frontendOptions;
    clang::InitializePreprocessor( pp, ppo, headerSearchOptions, frontendOptions );

    pp.getBuiltinInfo().InitializeBuiltins( pp.getIdentifierTable(), langOptions );

    llvm::MemoryBuffer* sourceBuffer = llvm::MemoryBuffer::getMemBufferCopy( code );
    sm.createMainFileIDForMemBuffer( sourceBuffer );

    clang::Builtin::Context bic( *ti );
    clang::ASTContext astc( langOptions, sm, *ti, 
                           pp.getIdentifierTable(), 
                           pp.getSelectorTable(), 
                           bic, 
                           0 );

    llvm::LLVMContext   lc;
    clang::CodeGenOptions codeGenOptions;
    llvm::OwningPtr<clang::CodeGenerator> cg;
    cg.reset( clang::CreateLLVMCodeGen( diag, "clang_test", codeGenOptions, lc ) );
    if( cg == NULL ) {
        printf( "could not create CodeGenerator\n" );
        return -1;
    }

    clang::ParseAST( pp, cg.get(), astc );
    if( tdp.getNumErrors() ) {
        printf( "error parsing AST\n" );
        return -2;
    }

    llvm::Module* new_module = cg->ReleaseModule();
    if( !new_module ) {
        printf( "error generating code\n" );
        return -2;
    }

    llvm::Linker    linker( "clang_test", "clang_test", lc, llvm::Linker::Verbose   );

    std::string error;
    if( linker.LinkInModule( new_module, &error ) || !error.empty() ) {
        printf( "link error\n" );
        return -3;
    }

    llvm::Module* composite_module = linker.getModule();
    if( composite_module == NULL ) {
        printf( "link error\n" );
        return -3;
    }

    llvm::ExecutionEngine *pEngine = llvm::ExecutionEngine::create( composite_module, 
                                                                   false,
                                                                   &error );
    if( !error.empty() || pEngine == NULL ) {
        printf( "error creating ExecutionEngine\n" );
        return -4;
    }

    llvm::Function* f = composite_module->getFunction( "main" );
    if( f == NULL ) {
        printf( "couldn't find main function\n" );
        return -5;
    }

    // This will abort with the message:
    // LLVM ERROR: Program used external function 'UnresolvedFunction' which could not be resolved!
    std::vector<llvm::GenericValue> params;
    llvm::GenericValue result = pEngine->runFunction( f, params );  

    printf( "function main returned %llu\n", result.IntVal.getZExtValue() );

    return 0;
}

Никаких ошибок нигде не происходит, пока мы не вызовем runFunction ближе к концу, что даст ошибку «LLVM ERROR: Программа использовала внешнюю функцию 'UnresolvedFunction', которую не удалось разрешить!» перед прерыванием.

Я ожидал, что LinkInModule или getModule выйдут из строя с какой-либо ошибкой, но это не так. Мой вопрос: есть ли способ определить, что у модуля есть неразрешенные внешние элементы, чтобы не сработать и не сгореть при попытке выполнить код? Я довольно долго копался в исходниках llvm и пока не могу найти то, что ищу.

Я использую llvm / clang 2.9 в Mac OS X (x86_64), если это важно .

Правка : Я нашел частную функцию под названием GetAllUndefinedSymbols в источниках llvm (llvm-2.9 / lib / Linker / LinkArchives.cpp), которая, похоже, делает то, что я хочу. Думаю, я надеялся, что для этого есть настоящий API, но я кое-что пропустил?

5
задан zpasternack 22 June 2011 в 05:40
поделиться