Я использую 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, что-то, что я пропустил?