//===----------------------------------------------------------------------===//
#include "llvm/AsmParser/Parser.h"
-#include "llvm/Linker/Linker.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Module.h"
+#include "llvm/Linker/Linker.h"
#include "llvm/Support/SourceMgr.h"
+#include "llvm-c/Linker.h"
#include "gtest/gtest.h"
using namespace llvm;
class LinkModuleTest : public testing::Test {
protected:
- virtual void SetUp() {
+ void SetUp() override {
M.reset(new Module("MyModule", Ctx));
FunctionType *FTy = FunctionType::get(
Type::getInt8PtrTy(Ctx), Type::getInt32Ty(Ctx), false /*=isVarArg*/);
SwitchCase2BB = BasicBlock::Create(Ctx, "switch.case.2", F);
ExitBB = BasicBlock::Create(Ctx, "exit", F);
- ArrayType *AT = ArrayType::get(Type::getInt8PtrTy(Ctx), 3);
+ AT = ArrayType::get(Type::getInt8PtrTy(Ctx), 3);
GV = new GlobalVariable(*M.get(), AT, false /*=isConstant*/,
GlobalValue::InternalLinkage, nullptr,"switch.bas");
GV->setInitializer(ConstantArray::get(AT, Init));
}
- virtual void TearDown() { M.reset(); }
+ void TearDown() override { M.reset(); }
LLVMContext Ctx;
std::unique_ptr<Module> M;
Function *F;
+ ArrayType *AT;
GlobalVariable *GV;
BasicBlock *EntryBB;
BasicBlock *SwitchCase1BB;
GEPIndices.push_back(ConstantInt::get(Type::getInt32Ty(Ctx), 0));
GEPIndices.push_back(F->arg_begin());
- Value *GEP = Builder.CreateGEP(GV, GEPIndices, "switch.gep");
+ Value *GEP = Builder.CreateGEP(AT, GV, GEPIndices, "switch.gep");
Value *Load = Builder.CreateLoad(GEP, "switch.load");
Builder.CreateRet(Load);
delete LinkedModule;
}
+static Module *getExternal(LLVMContext &Ctx, StringRef FuncName) {
+ // Create a module with an empty externally-linked function
+ Module *M = new Module("ExternalModule", Ctx);
+ FunctionType *FTy = FunctionType::get(
+ Type::getVoidTy(Ctx), Type::getInt8PtrTy(Ctx), false /*=isVarArgs*/);
+
+ Function *F =
+ Function::Create(FTy, Function::ExternalLinkage, FuncName, M);
+ F->setCallingConv(CallingConv::C);
+
+ BasicBlock *BB = BasicBlock::Create(Ctx, "", F);
+ IRBuilder<> Builder(BB);
+ Builder.CreateRetVoid();
+ return M;
+}
+
static Module *getInternal(LLVMContext &Ctx) {
Module *InternalM = new Module("InternalModule", Ctx);
FunctionType *FTy = FunctionType::get(
M1->getNamedGlobal("t2")->getType());
}
+TEST_F(LinkModuleTest, CAPISuccess) {
+ std::unique_ptr<Module> DestM(getExternal(Ctx, "foo"));
+ std::unique_ptr<Module> SourceM(getExternal(Ctx, "bar"));
+ char *errout = nullptr;
+ LLVMBool result = LLVMLinkModules(wrap(DestM.get()), wrap(SourceM.get()),
+ LLVMLinkerDestroySource, &errout);
+ EXPECT_EQ(0, result);
+ EXPECT_EQ(nullptr, errout);
+ // "bar" is present in destination module
+ EXPECT_NE(nullptr, DestM->getFunction("bar"));
+}
+
+TEST_F(LinkModuleTest, CAPIFailure) {
+ // Symbol clash between two modules
+ std::unique_ptr<Module> DestM(getExternal(Ctx, "foo"));
+ std::unique_ptr<Module> SourceM(getExternal(Ctx, "foo"));
+ char *errout = nullptr;
+ LLVMBool result = LLVMLinkModules(wrap(DestM.get()), wrap(SourceM.get()),
+ LLVMLinkerDestroySource, &errout);
+ EXPECT_EQ(1, result);
+ EXPECT_STREQ("Linking globals named 'foo': symbol multiply defined!", errout);
+}
+
} // end anonymous namespace