void IRGenModule::addLinkLibrary(const LinkLibrary &linkLib) { llvm::LLVMContext &ctx = Module.getContext(); switch (linkLib.getKind()) { case LibraryKind::Library: { llvm::SmallString<32> opt = getTargetDependentLibraryOption(Triple, linkLib.getName()); AutolinkEntries.push_back( llvm::MDNode::get(ctx, llvm::MDString::get(ctx, opt))); break; } case LibraryKind::Framework: { // If we're supposed to disable autolinking of this framework, bail out. auto &frameworks = IRGen.Opts.DisableAutolinkFrameworks; if (std::find(frameworks.begin(), frameworks.end(), linkLib.getName()) != frameworks.end()) return; llvm::Metadata *args[] = { llvm::MDString::get(ctx, "-framework"), llvm::MDString::get(ctx, linkLib.getName()) }; AutolinkEntries.push_back(llvm::MDNode::get(ctx, args)); break; } } if (linkLib.shouldForceLoad()) { llvm::SmallString<64> buf; encodeForceLoadSymbolName(buf, linkLib.getName()); auto ForceImportThunk = Module.getOrInsertFunction(buf, llvm::FunctionType::get(VoidTy, false)); if (useDllStorage()) cast<llvm::GlobalValue>(ForceImportThunk) ->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass); buf += "_$"; appendEncodedName(buf, IRGen.Opts.ModuleName); if (!Module.getGlobalVariable(buf.str())) { auto ref = new llvm::GlobalVariable(Module, ForceImportThunk->getType(), /*isConstant=*/true, llvm::GlobalValue::WeakAnyLinkage, ForceImportThunk, buf.str()); ref->setVisibility(llvm::GlobalValue::HiddenVisibility); auto casted = llvm::ConstantExpr::getBitCast(ref, Int8PtrTy); LLVMUsed.push_back(casted); } } }
void IRGenModule::addLinkLibrary(const LinkLibrary &linkLib) { llvm::LLVMContext &ctx = Module.getContext(); switch (linkLib.getKind()) { case LibraryKind::Library: { // FIXME: Use target-independent linker option. // Clang uses CGM.getTargetCodeGenInfo().getDependentLibraryOption(...). llvm::SmallString<32> buf; buf += "-l"; buf += linkLib.getName(); auto flag = llvm::MDString::get(ctx, buf); AutolinkEntries.push_back(llvm::MDNode::get(ctx, flag)); break; } case LibraryKind::Framework: { // If we're supposed to disable autolinking of this framework, bail out. auto &frameworks = IRGen.Opts.DisableAutolinkFrameworks; if (std::find(frameworks.begin(), frameworks.end(), linkLib.getName()) != frameworks.end()) return; llvm::Metadata *args[] = { llvm::MDString::get(ctx, "-framework"), llvm::MDString::get(ctx, linkLib.getName()) }; AutolinkEntries.push_back(llvm::MDNode::get(ctx, args)); break; } } if (linkLib.shouldForceLoad()) { llvm::SmallString<64> buf; encodeForceLoadSymbolName(buf, linkLib.getName()); auto symbolAddr = Module.getOrInsertGlobal(buf.str(), Int1Ty); buf += "_$"; appendEncodedName(buf, IRGen.Opts.ModuleName); if (!Module.getGlobalVariable(buf.str())) { auto ref = new llvm::GlobalVariable(Module, symbolAddr->getType(), /*constant=*/true, llvm::GlobalValue::WeakAnyLinkage, symbolAddr, buf.str()); ref->setVisibility(llvm::GlobalValue::HiddenVisibility); auto casted = llvm::ConstantExpr::getBitCast(ref, Int8PtrTy); LLVMUsed.push_back(casted); } } }
static bool tryLoadLibrary(LinkLibrary linkLib, SearchPathOptions searchPathOpts) { llvm::SmallString<128> path = linkLib.getName(); // If we have an absolute or relative path, just try to load it now. if (llvm::sys::path::has_parent_path(path.str())) { #if WIN32 return LoadLibrary(path.c_str()); #else return dlopen(path.c_str(), RTLD_LAZY | RTLD_GLOBAL); #endif } bool success = false; switch (linkLib.getKind()) { case LibraryKind::Library: { llvm::SmallString<32> stem; if (llvm::sys::path::has_extension(path.str())) { stem = std::move(path); } else { // FIXME: Try the appropriate extension for the current platform? stem = "lib"; stem += path; stem += LTDL_SHLIB_EXT; } // Try user-provided library search paths first. for (auto &libDir : searchPathOpts.LibrarySearchPaths) { path = libDir; llvm::sys::path::append(path, stem.str()); #if WIN32 success = LoadLibrary(path.c_str()); #else success = dlopen(path.c_str(), RTLD_LAZY | RTLD_GLOBAL); #endif if (success) break; } // Let dlopen determine the best search paths. if (!success) #if WIN32 success = LoadLibrary(stem.c_str()); #else success = dlopen(stem.c_str(), RTLD_LAZY | RTLD_GLOBAL); #endif // If that fails, try our runtime library path. if (!success) success = loadRuntimeLib(stem, searchPathOpts.RuntimeLibraryPath); break; } case LibraryKind::Framework: { // If we have a framework, mangle the name to point to the framework // binary. llvm::SmallString<64> frameworkPart{std::move(path)}; frameworkPart += ".framework"; llvm::sys::path::append(frameworkPart, linkLib.getName()); // Try user-provided framework search paths first; frameworks contain // binaries as well as modules. for (auto &frameworkDir : searchPathOpts.FrameworkSearchPaths) { path = frameworkDir; llvm::sys::path::append(path, frameworkPart.str()); #if WIN32 success = LoadLibrary(path.c_str()); #else success = dlopen(path.c_str(), RTLD_LAZY | RTLD_GLOBAL); #endif if (success) break; } // If that fails, let dlopen search for system frameworks. if (!success) #if WIN32 success = LoadLibrary(frameworkPart.c_str()); #else success = dlopen(frameworkPart.c_str(), RTLD_LAZY | RTLD_GLOBAL); #endif break; } } return success; }