123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629 |
- //===- lib/Linker/LinkModules.cpp - Module Linker Implementation ----------===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // This file implements the LLVM module linker.
- //
- //===----------------------------------------------------------------------===//
- #include "LinkDiagnosticInfo.h"
- #include "llvm-c/Linker.h"
- #include "llvm/ADT/SetVector.h"
- #include "llvm/IR/Comdat.h"
- #include "llvm/IR/DiagnosticPrinter.h"
- #include "llvm/IR/GlobalValue.h"
- #include "llvm/IR/LLVMContext.h"
- #include "llvm/IR/Module.h"
- #include "llvm/Linker/Linker.h"
- #include "llvm/Support/Error.h"
- using namespace llvm;
- namespace {
- enum class LinkFrom { Dst, Src, Both };
- /// This is an implementation class for the LinkModules function, which is the
- /// entrypoint for this file.
- class ModuleLinker {
- IRMover &Mover;
- std::unique_ptr<Module> SrcM;
- SetVector<GlobalValue *> ValuesToLink;
- /// For symbol clashes, prefer those from Src.
- unsigned Flags;
- /// List of global value names that should be internalized.
- StringSet<> Internalize;
- /// Function that will perform the actual internalization. The reason for a
- /// callback is that the linker cannot call internalizeModule without
- /// creating a circular dependency between IPO and the linker.
- std::function<void(Module &, const StringSet<> &)> InternalizeCallback;
- /// Used as the callback for lazy linking.
- /// The mover has just hit GV and we have to decide if it, and other members
- /// of the same comdat, should be linked. Every member to be linked is passed
- /// to Add.
- void addLazyFor(GlobalValue &GV, const IRMover::ValueAdder &Add);
- bool shouldOverrideFromSrc() { return Flags & Linker::OverrideFromSrc; }
- bool shouldLinkOnlyNeeded() { return Flags & Linker::LinkOnlyNeeded; }
- bool shouldLinkFromSource(bool &LinkFromSrc, const GlobalValue &Dest,
- const GlobalValue &Src);
- /// Should we have mover and linker error diag info?
- bool emitError(const Twine &Message) {
- SrcM->getContext().diagnose(LinkDiagnosticInfo(DS_Error, Message));
- return true;
- }
- bool getComdatLeader(Module &M, StringRef ComdatName,
- const GlobalVariable *&GVar);
- bool computeResultingSelectionKind(StringRef ComdatName,
- Comdat::SelectionKind Src,
- Comdat::SelectionKind Dst,
- Comdat::SelectionKind &Result,
- LinkFrom &From);
- DenseMap<const Comdat *, std::pair<Comdat::SelectionKind, LinkFrom>>
- ComdatsChosen;
- bool getComdatResult(const Comdat *SrcC, Comdat::SelectionKind &SK,
- LinkFrom &From);
- // Keep track of the lazy linked global members of each comdat in source.
- DenseMap<const Comdat *, std::vector<GlobalValue *>> LazyComdatMembers;
- /// Given a global in the source module, return the global in the
- /// destination module that is being linked to, if any.
- GlobalValue *getLinkedToGlobal(const GlobalValue *SrcGV) {
- Module &DstM = Mover.getModule();
- // If the source has no name it can't link. If it has local linkage,
- // there is no name match-up going on.
- if (!SrcGV->hasName() || GlobalValue::isLocalLinkage(SrcGV->getLinkage()))
- return nullptr;
- // Otherwise see if we have a match in the destination module's symtab.
- GlobalValue *DGV = DstM.getNamedValue(SrcGV->getName());
- if (!DGV)
- return nullptr;
- // If we found a global with the same name in the dest module, but it has
- // internal linkage, we are really not doing any linkage here.
- if (DGV->hasLocalLinkage())
- return nullptr;
- // Otherwise, we do in fact link to the destination global.
- return DGV;
- }
- /// Drop GV if it is a member of a comdat that we are dropping.
- /// This can happen with COFF's largest selection kind.
- void dropReplacedComdat(GlobalValue &GV,
- const DenseSet<const Comdat *> &ReplacedDstComdats);
- bool linkIfNeeded(GlobalValue &GV, SmallVectorImpl<GlobalValue *> &GVToClone);
- public:
- ModuleLinker(IRMover &Mover, std::unique_ptr<Module> SrcM, unsigned Flags,
- std::function<void(Module &, const StringSet<> &)>
- InternalizeCallback = {})
- : Mover(Mover), SrcM(std::move(SrcM)), Flags(Flags),
- InternalizeCallback(std::move(InternalizeCallback)) {}
- bool run();
- };
- } // namespace
- static GlobalValue::VisibilityTypes
- getMinVisibility(GlobalValue::VisibilityTypes A,
- GlobalValue::VisibilityTypes B) {
- if (A == GlobalValue::HiddenVisibility || B == GlobalValue::HiddenVisibility)
- return GlobalValue::HiddenVisibility;
- if (A == GlobalValue::ProtectedVisibility ||
- B == GlobalValue::ProtectedVisibility)
- return GlobalValue::ProtectedVisibility;
- return GlobalValue::DefaultVisibility;
- }
- bool ModuleLinker::getComdatLeader(Module &M, StringRef ComdatName,
- const GlobalVariable *&GVar) {
- const GlobalValue *GVal = M.getNamedValue(ComdatName);
- if (const auto *GA = dyn_cast_or_null<GlobalAlias>(GVal)) {
- GVal = GA->getAliaseeObject();
- if (!GVal)
- // We cannot resolve the size of the aliasee yet.
- return emitError("Linking COMDATs named '" + ComdatName +
- "': COMDAT key involves incomputable alias size.");
- }
- GVar = dyn_cast_or_null<GlobalVariable>(GVal);
- if (!GVar)
- return emitError(
- "Linking COMDATs named '" + ComdatName +
- "': GlobalVariable required for data dependent selection!");
- return false;
- }
- bool ModuleLinker::computeResultingSelectionKind(StringRef ComdatName,
- Comdat::SelectionKind Src,
- Comdat::SelectionKind Dst,
- Comdat::SelectionKind &Result,
- LinkFrom &From) {
- Module &DstM = Mover.getModule();
- // The ability to mix Comdat::SelectionKind::Any with
- // Comdat::SelectionKind::Largest is a behavior that comes from COFF.
- bool DstAnyOrLargest = Dst == Comdat::SelectionKind::Any ||
- Dst == Comdat::SelectionKind::Largest;
- bool SrcAnyOrLargest = Src == Comdat::SelectionKind::Any ||
- Src == Comdat::SelectionKind::Largest;
- if (DstAnyOrLargest && SrcAnyOrLargest) {
- if (Dst == Comdat::SelectionKind::Largest ||
- Src == Comdat::SelectionKind::Largest)
- Result = Comdat::SelectionKind::Largest;
- else
- Result = Comdat::SelectionKind::Any;
- } else if (Src == Dst) {
- Result = Dst;
- } else {
- return emitError("Linking COMDATs named '" + ComdatName +
- "': invalid selection kinds!");
- }
- switch (Result) {
- case Comdat::SelectionKind::Any:
- // Go with Dst.
- From = LinkFrom::Dst;
- break;
- case Comdat::SelectionKind::NoDeduplicate:
- From = LinkFrom::Both;
- break;
- case Comdat::SelectionKind::ExactMatch:
- case Comdat::SelectionKind::Largest:
- case Comdat::SelectionKind::SameSize: {
- const GlobalVariable *DstGV;
- const GlobalVariable *SrcGV;
- if (getComdatLeader(DstM, ComdatName, DstGV) ||
- getComdatLeader(*SrcM, ComdatName, SrcGV))
- return true;
- const DataLayout &DstDL = DstM.getDataLayout();
- const DataLayout &SrcDL = SrcM->getDataLayout();
- uint64_t DstSize = DstDL.getTypeAllocSize(DstGV->getValueType());
- uint64_t SrcSize = SrcDL.getTypeAllocSize(SrcGV->getValueType());
- if (Result == Comdat::SelectionKind::ExactMatch) {
- if (SrcGV->getInitializer() != DstGV->getInitializer())
- return emitError("Linking COMDATs named '" + ComdatName +
- "': ExactMatch violated!");
- From = LinkFrom::Dst;
- } else if (Result == Comdat::SelectionKind::Largest) {
- From = SrcSize > DstSize ? LinkFrom::Src : LinkFrom::Dst;
- } else if (Result == Comdat::SelectionKind::SameSize) {
- if (SrcSize != DstSize)
- return emitError("Linking COMDATs named '" + ComdatName +
- "': SameSize violated!");
- From = LinkFrom::Dst;
- } else {
- llvm_unreachable("unknown selection kind");
- }
- break;
- }
- }
- return false;
- }
- bool ModuleLinker::getComdatResult(const Comdat *SrcC,
- Comdat::SelectionKind &Result,
- LinkFrom &From) {
- Module &DstM = Mover.getModule();
- Comdat::SelectionKind SSK = SrcC->getSelectionKind();
- StringRef ComdatName = SrcC->getName();
- Module::ComdatSymTabType &ComdatSymTab = DstM.getComdatSymbolTable();
- Module::ComdatSymTabType::iterator DstCI = ComdatSymTab.find(ComdatName);
- if (DstCI == ComdatSymTab.end()) {
- // Use the comdat if it is only available in one of the modules.
- From = LinkFrom::Src;
- Result = SSK;
- return false;
- }
- const Comdat *DstC = &DstCI->second;
- Comdat::SelectionKind DSK = DstC->getSelectionKind();
- return computeResultingSelectionKind(ComdatName, SSK, DSK, Result, From);
- }
- bool ModuleLinker::shouldLinkFromSource(bool &LinkFromSrc,
- const GlobalValue &Dest,
- const GlobalValue &Src) {
- // Should we unconditionally use the Src?
- if (shouldOverrideFromSrc()) {
- LinkFromSrc = true;
- return false;
- }
- // We always have to add Src if it has appending linkage.
- if (Src.hasAppendingLinkage() || Dest.hasAppendingLinkage()) {
- LinkFromSrc = true;
- return false;
- }
- bool SrcIsDeclaration = Src.isDeclarationForLinker();
- bool DestIsDeclaration = Dest.isDeclarationForLinker();
- if (SrcIsDeclaration) {
- // If Src is external or if both Src & Dest are external.. Just link the
- // external globals, we aren't adding anything.
- if (Src.hasDLLImportStorageClass()) {
- // If one of GVs is marked as DLLImport, result should be dllimport'ed.
- LinkFromSrc = DestIsDeclaration;
- return false;
- }
- // If the Dest is weak, use the source linkage.
- if (Dest.hasExternalWeakLinkage()) {
- LinkFromSrc = true;
- return false;
- }
- // Link an available_externally over a declaration.
- LinkFromSrc = !Src.isDeclaration() && Dest.isDeclaration();
- return false;
- }
- if (DestIsDeclaration) {
- // If Dest is external but Src is not:
- LinkFromSrc = true;
- return false;
- }
- if (Src.hasCommonLinkage()) {
- if (Dest.hasLinkOnceLinkage() || Dest.hasWeakLinkage()) {
- LinkFromSrc = true;
- return false;
- }
- if (!Dest.hasCommonLinkage()) {
- LinkFromSrc = false;
- return false;
- }
- const DataLayout &DL = Dest.getParent()->getDataLayout();
- uint64_t DestSize = DL.getTypeAllocSize(Dest.getValueType());
- uint64_t SrcSize = DL.getTypeAllocSize(Src.getValueType());
- LinkFromSrc = SrcSize > DestSize;
- return false;
- }
- if (Src.isWeakForLinker()) {
- assert(!Dest.hasExternalWeakLinkage());
- assert(!Dest.hasAvailableExternallyLinkage());
- if (Dest.hasLinkOnceLinkage() && Src.hasWeakLinkage()) {
- LinkFromSrc = true;
- return false;
- }
- LinkFromSrc = false;
- return false;
- }
- if (Dest.isWeakForLinker()) {
- assert(Src.hasExternalLinkage());
- LinkFromSrc = true;
- return false;
- }
- assert(!Src.hasExternalWeakLinkage());
- assert(!Dest.hasExternalWeakLinkage());
- assert(Dest.hasExternalLinkage() && Src.hasExternalLinkage() &&
- "Unexpected linkage type!");
- return emitError("Linking globals named '" + Src.getName() +
- "': symbol multiply defined!");
- }
- bool ModuleLinker::linkIfNeeded(GlobalValue &GV,
- SmallVectorImpl<GlobalValue *> &GVToClone) {
- GlobalValue *DGV = getLinkedToGlobal(&GV);
- if (shouldLinkOnlyNeeded()) {
- // Always import variables with appending linkage.
- if (!GV.hasAppendingLinkage()) {
- // Don't import globals unless they are referenced by the destination
- // module.
- if (!DGV)
- return false;
- // Don't import globals that are already defined in the destination module
- if (!DGV->isDeclaration())
- return false;
- }
- }
- if (DGV && !GV.hasLocalLinkage() && !GV.hasAppendingLinkage()) {
- auto *DGVar = dyn_cast<GlobalVariable>(DGV);
- auto *SGVar = dyn_cast<GlobalVariable>(&GV);
- if (DGVar && SGVar) {
- if (DGVar->isDeclaration() && SGVar->isDeclaration() &&
- (!DGVar->isConstant() || !SGVar->isConstant())) {
- DGVar->setConstant(false);
- SGVar->setConstant(false);
- }
- if (DGVar->hasCommonLinkage() && SGVar->hasCommonLinkage()) {
- MaybeAlign Align(
- std::max(DGVar->getAlignment(), SGVar->getAlignment()));
- SGVar->setAlignment(Align);
- DGVar->setAlignment(Align);
- }
- }
- GlobalValue::VisibilityTypes Visibility =
- getMinVisibility(DGV->getVisibility(), GV.getVisibility());
- DGV->setVisibility(Visibility);
- GV.setVisibility(Visibility);
- GlobalValue::UnnamedAddr UnnamedAddr = GlobalValue::getMinUnnamedAddr(
- DGV->getUnnamedAddr(), GV.getUnnamedAddr());
- DGV->setUnnamedAddr(UnnamedAddr);
- GV.setUnnamedAddr(UnnamedAddr);
- }
- if (!DGV && !shouldOverrideFromSrc() &&
- (GV.hasLocalLinkage() || GV.hasLinkOnceLinkage() ||
- GV.hasAvailableExternallyLinkage()))
- return false;
- if (GV.isDeclaration())
- return false;
- LinkFrom ComdatFrom = LinkFrom::Dst;
- if (const Comdat *SC = GV.getComdat()) {
- std::tie(std::ignore, ComdatFrom) = ComdatsChosen[SC];
- if (ComdatFrom == LinkFrom::Dst)
- return false;
- }
- bool LinkFromSrc = true;
- if (DGV && shouldLinkFromSource(LinkFromSrc, *DGV, GV))
- return true;
- if (DGV && ComdatFrom == LinkFrom::Both)
- GVToClone.push_back(LinkFromSrc ? DGV : &GV);
- if (LinkFromSrc)
- ValuesToLink.insert(&GV);
- return false;
- }
- void ModuleLinker::addLazyFor(GlobalValue &GV, const IRMover::ValueAdder &Add) {
- // Add these to the internalize list
- if (!GV.hasLinkOnceLinkage() && !GV.hasAvailableExternallyLinkage() &&
- !shouldLinkOnlyNeeded())
- return;
- if (InternalizeCallback)
- Internalize.insert(GV.getName());
- Add(GV);
- const Comdat *SC = GV.getComdat();
- if (!SC)
- return;
- for (GlobalValue *GV2 : LazyComdatMembers[SC]) {
- GlobalValue *DGV = getLinkedToGlobal(GV2);
- bool LinkFromSrc = true;
- if (DGV && shouldLinkFromSource(LinkFromSrc, *DGV, *GV2))
- return;
- if (!LinkFromSrc)
- continue;
- if (InternalizeCallback)
- Internalize.insert(GV2->getName());
- Add(*GV2);
- }
- }
- void ModuleLinker::dropReplacedComdat(
- GlobalValue &GV, const DenseSet<const Comdat *> &ReplacedDstComdats) {
- Comdat *C = GV.getComdat();
- if (!C)
- return;
- if (!ReplacedDstComdats.count(C))
- return;
- if (GV.use_empty()) {
- GV.eraseFromParent();
- return;
- }
- if (auto *F = dyn_cast<Function>(&GV)) {
- F->deleteBody();
- } else if (auto *Var = dyn_cast<GlobalVariable>(&GV)) {
- Var->setInitializer(nullptr);
- } else {
- auto &Alias = cast<GlobalAlias>(GV);
- Module &M = *Alias.getParent();
- GlobalValue *Declaration;
- if (auto *FTy = dyn_cast<FunctionType>(Alias.getValueType())) {
- Declaration = Function::Create(FTy, GlobalValue::ExternalLinkage, "", &M);
- } else {
- Declaration =
- new GlobalVariable(M, Alias.getValueType(), /*isConstant*/ false,
- GlobalValue::ExternalLinkage,
- /*Initializer*/ nullptr);
- }
- Declaration->takeName(&Alias);
- Alias.replaceAllUsesWith(Declaration);
- Alias.eraseFromParent();
- }
- }
- bool ModuleLinker::run() {
- Module &DstM = Mover.getModule();
- DenseSet<const Comdat *> ReplacedDstComdats;
- for (const auto &SMEC : SrcM->getComdatSymbolTable()) {
- const Comdat &C = SMEC.getValue();
- if (ComdatsChosen.count(&C))
- continue;
- Comdat::SelectionKind SK;
- LinkFrom From;
- if (getComdatResult(&C, SK, From))
- return true;
- ComdatsChosen[&C] = std::make_pair(SK, From);
- if (From != LinkFrom::Src)
- continue;
- Module::ComdatSymTabType &ComdatSymTab = DstM.getComdatSymbolTable();
- Module::ComdatSymTabType::iterator DstCI = ComdatSymTab.find(C.getName());
- if (DstCI == ComdatSymTab.end())
- continue;
- // The source comdat is replacing the dest one.
- const Comdat *DstC = &DstCI->second;
- ReplacedDstComdats.insert(DstC);
- }
- // Alias have to go first, since we are not able to find their comdats
- // otherwise.
- for (GlobalAlias &GV : llvm::make_early_inc_range(DstM.aliases()))
- dropReplacedComdat(GV, ReplacedDstComdats);
- for (GlobalVariable &GV : llvm::make_early_inc_range(DstM.globals()))
- dropReplacedComdat(GV, ReplacedDstComdats);
- for (Function &GV : llvm::make_early_inc_range(DstM))
- dropReplacedComdat(GV, ReplacedDstComdats);
- for (GlobalVariable &GV : SrcM->globals())
- if (GV.hasLinkOnceLinkage())
- if (const Comdat *SC = GV.getComdat())
- LazyComdatMembers[SC].push_back(&GV);
- for (Function &SF : *SrcM)
- if (SF.hasLinkOnceLinkage())
- if (const Comdat *SC = SF.getComdat())
- LazyComdatMembers[SC].push_back(&SF);
- for (GlobalAlias &GA : SrcM->aliases())
- if (GA.hasLinkOnceLinkage())
- if (const Comdat *SC = GA.getComdat())
- LazyComdatMembers[SC].push_back(&GA);
- // Insert all of the globals in src into the DstM module... without linking
- // initializers (which could refer to functions not yet mapped over).
- SmallVector<GlobalValue *, 0> GVToClone;
- for (GlobalVariable &GV : SrcM->globals())
- if (linkIfNeeded(GV, GVToClone))
- return true;
- for (Function &SF : *SrcM)
- if (linkIfNeeded(SF, GVToClone))
- return true;
- for (GlobalAlias &GA : SrcM->aliases())
- if (linkIfNeeded(GA, GVToClone))
- return true;
- for (GlobalIFunc &GI : SrcM->ifuncs())
- if (linkIfNeeded(GI, GVToClone))
- return true;
- // For a variable in a comdat nodeduplicate, its initializer should be
- // preserved (its content may be implicitly used by other members) even if
- // symbol resolution does not pick it. Clone it into an unnamed private
- // variable.
- for (GlobalValue *GV : GVToClone) {
- if (auto *Var = dyn_cast<GlobalVariable>(GV)) {
- auto *NewVar = new GlobalVariable(*Var->getParent(), Var->getValueType(),
- Var->isConstant(), Var->getLinkage(),
- Var->getInitializer());
- NewVar->copyAttributesFrom(Var);
- NewVar->setVisibility(GlobalValue::DefaultVisibility);
- NewVar->setLinkage(GlobalValue::PrivateLinkage);
- NewVar->setDSOLocal(true);
- NewVar->setComdat(Var->getComdat());
- if (Var->getParent() != &Mover.getModule())
- ValuesToLink.insert(NewVar);
- } else {
- emitError("linking '" + GV->getName() +
- "': non-variables in comdat nodeduplicate are not handled");
- }
- }
- for (unsigned I = 0; I < ValuesToLink.size(); ++I) {
- GlobalValue *GV = ValuesToLink[I];
- const Comdat *SC = GV->getComdat();
- if (!SC)
- continue;
- for (GlobalValue *GV2 : LazyComdatMembers[SC]) {
- GlobalValue *DGV = getLinkedToGlobal(GV2);
- bool LinkFromSrc = true;
- if (DGV && shouldLinkFromSource(LinkFromSrc, *DGV, *GV2))
- return true;
- if (LinkFromSrc)
- ValuesToLink.insert(GV2);
- }
- }
- if (InternalizeCallback) {
- for (GlobalValue *GV : ValuesToLink)
- Internalize.insert(GV->getName());
- }
- // FIXME: Propagate Errors through to the caller instead of emitting
- // diagnostics.
- bool HasErrors = false;
- if (Error E = Mover.move(std::move(SrcM), ValuesToLink.getArrayRef(),
- [this](GlobalValue &GV, IRMover::ValueAdder Add) {
- addLazyFor(GV, Add);
- },
- /* IsPerformingImport */ false)) {
- handleAllErrors(std::move(E), [&](ErrorInfoBase &EIB) {
- DstM.getContext().diagnose(LinkDiagnosticInfo(DS_Error, EIB.message()));
- HasErrors = true;
- });
- }
- if (HasErrors)
- return true;
- if (InternalizeCallback)
- InternalizeCallback(DstM, Internalize);
- return false;
- }
- Linker::Linker(Module &M) : Mover(M) {}
- bool Linker::linkInModule(
- std::unique_ptr<Module> Src, unsigned Flags,
- std::function<void(Module &, const StringSet<> &)> InternalizeCallback) {
- ModuleLinker ModLinker(Mover, std::move(Src), Flags,
- std::move(InternalizeCallback));
- return ModLinker.run();
- }
- //===----------------------------------------------------------------------===//
- // LinkModules entrypoint.
- //===----------------------------------------------------------------------===//
- /// This function links two modules together, with the resulting Dest module
- /// modified to be the composite of the two input modules. If an error occurs,
- /// true is returned and ErrorMsg (if not null) is set to indicate the problem.
- /// Upon failure, the Dest module could be in a modified state, and shouldn't be
- /// relied on to be consistent.
- bool Linker::linkModules(
- Module &Dest, std::unique_ptr<Module> Src, unsigned Flags,
- std::function<void(Module &, const StringSet<> &)> InternalizeCallback) {
- Linker L(Dest);
- return L.linkInModule(std::move(Src), Flags, std::move(InternalizeCallback));
- }
- //===----------------------------------------------------------------------===//
- // C API.
- //===----------------------------------------------------------------------===//
- LLVMBool LLVMLinkModules2(LLVMModuleRef Dest, LLVMModuleRef Src) {
- Module *D = unwrap(Dest);
- std::unique_ptr<Module> M(unwrap(Src));
- return Linker::linkModules(*D, std::move(M));
- }
|