使用llvm :: Linker以编程方式查找未解析的外部

zpa*_*ack 5 c c++ linker llvm clang

我正在使用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;
}
Run Code Online (Sandbox Code Playgroud)

在我们在结尾附近调用runFunction之前,没有任何错误发生,这会产生错误"LLVM错误:程序使用的外部函数'UnresolvedFunction'无法解决!" 在流产之前.

我有点期望LinkInModule或getModule失败并出现一些错误,但事实并非如此.我的问题是:有没有办法确定模块是否有未解析的外部,以免在尝试执行代码时崩溃和烧毁?我已经花了很长一段时间来浏览llvm源码,到目前为止还找不到我想要的东西.

我在Mac OS X(x86_64)上使用llvm/clang 2.9,如果这很重要的话.

编辑:我发现了一个GetAllUndefinedSymbols在llvm源代码中调用的私有函数(llvm-2.9/lib/Linker/LinkArchives.cpp),这似乎是我想做的.我想我希望有一个实际的API,我错过了什么?

ser*_*rvn 2

IIRC,没有人要求过这样的 API,所以不存在。无论如何,我不完全确定您会使用这样的 API 做什么...任何重要的程序都会引用任何 .bc 文件中未定义的符号,例如malloc.

如果您确实想检查,类似以下内容应该有效:

for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I)
  if (I->isDeclaration())
    UndefGlobals.insert(&*I);

for (Module::global_iterator I = M->global_begin(),
                             E = M->global_end();
     I != E; ++I)
  if (I->isDeclaration())
    UndefGlobals.insert(&*I);
Run Code Online (Sandbox Code Playgroud)