//===- lib/Driver/DarwinLdDriver.cpp --------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// /// /// \file /// /// Concrete instance of the Driver for darwin's ld. /// //===----------------------------------------------------------------------===// #include "lld/Core/File.h" #include "lld/Core/ArchiveLibraryFile.h" #include "lld/Core/SharedLibraryFile.h" #include "lld/Driver/Driver.h" #include "lld/ReaderWriter/MachOLinkingContext.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Triple.h" #include "llvm/Option/Arg.h" #include "llvm/Option/Option.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Format.h" #include "llvm/Support/Host.h" #include "llvm/Support/MachO.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/Path.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Signals.h" #include "llvm/Support/raw_ostream.h" #include using namespace lld; namespace { // Create enum with OPT_xxx values for each option in DarwinLdOptions.td enum { OPT_INVALID = 0, #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ HELP, META) \ OPT_##ID, #include "DarwinLdOptions.inc" #undef OPTION }; // Create prefix string literals used in DarwinLdOptions.td #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; #include "DarwinLdOptions.inc" #undef PREFIX // Create table mapping all options defined in DarwinLdOptions.td static const llvm::opt::OptTable::Info infoTable[] = { #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ HELPTEXT, METAVAR) \ { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \ PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS }, #include "DarwinLdOptions.inc" #undef OPTION }; // Create OptTable class for parsing actual command line arguments class DarwinLdOptTable : public llvm::opt::OptTable { public: DarwinLdOptTable() : OptTable(infoTable, llvm::array_lengthof(infoTable)){} }; std::vector> loadFile(MachOLinkingContext &ctx, StringRef path, raw_ostream &diag, bool wholeArchive, bool upwardDylib) { if (ctx.logInputFiles()) diag << path << "\n"; ErrorOr> mbOrErr = ctx.getMemoryBuffer(path); if (std::error_code ec = mbOrErr.getError()) return makeErrorFile(path, ec); std::vector> files; if (std::error_code ec = ctx.registry().loadFile(std::move(mbOrErr.get()), files)) return makeErrorFile(path, ec); for (std::unique_ptr &pf : files) { // If file is a dylib, inform LinkingContext about it. if (SharedLibraryFile *shl = dyn_cast(pf.get())) { if (std::error_code ec = shl->parse()) return makeErrorFile(path, ec); ctx.registerDylib(reinterpret_cast(shl), upwardDylib); } } if (wholeArchive) return parseMemberFiles(files); return files; } } // anonymous namespace // Test may be running on Windows. Canonicalize the path // separator to '/' to get consistent outputs for tests. static std::string canonicalizePath(StringRef path) { char sep = llvm::sys::path::get_separator().front(); if (sep != '/') { std::string fixedPath = path; std::replace(fixedPath.begin(), fixedPath.end(), sep, '/'); return fixedPath; } else { return path; } } static void addFile(StringRef path, MachOLinkingContext &ctx, bool loadWholeArchive, bool upwardDylib, raw_ostream &diag) { std::vector> files = loadFile(ctx, path, diag, loadWholeArchive, upwardDylib); for (std::unique_ptr &file : files) ctx.getNodes().push_back(llvm::make_unique(std::move(file))); } // Export lists are one symbol per line. Blank lines are ignored. // Trailing comments start with #. static std::error_code parseExportsList(StringRef exportFilePath, MachOLinkingContext &ctx, raw_ostream &diagnostics) { // Map in export list file. ErrorOr> mb = MemoryBuffer::getFileOrSTDIN(exportFilePath); if (std::error_code ec = mb.getError()) return ec; ctx.addInputFileDependency(exportFilePath); StringRef buffer = mb->get()->getBuffer(); while (!buffer.empty()) { // Split off each line in the file. std::pair lineAndRest = buffer.split('\n'); StringRef line = lineAndRest.first; // Ignore trailing # comments. std::pair symAndComment = line.split('#'); StringRef sym = symAndComment.first.trim(); if (!sym.empty()) ctx.addExportSymbol(sym); buffer = lineAndRest.second; } return std::error_code(); } /// Order files are one symbol per line. Blank lines are ignored. /// Trailing comments start with #. Symbol names can be prefixed with an /// architecture name and/or .o leaf name. Examples: /// _foo /// bar.o:_bar /// libfrob.a(bar.o):_bar /// x86_64:_foo64 static std::error_code parseOrderFile(StringRef orderFilePath, MachOLinkingContext &ctx, raw_ostream &diagnostics) { // Map in order file. ErrorOr> mb = MemoryBuffer::getFileOrSTDIN(orderFilePath); if (std::error_code ec = mb.getError()) return ec; ctx.addInputFileDependency(orderFilePath); StringRef buffer = mb->get()->getBuffer(); while (!buffer.empty()) { // Split off each line in the file. std::pair lineAndRest = buffer.split('\n'); StringRef line = lineAndRest.first; buffer = lineAndRest.second; // Ignore trailing # comments. std::pair symAndComment = line.split('#'); if (symAndComment.first.empty()) continue; StringRef sym = symAndComment.first.trim(); if (sym.empty()) continue; // Check for prefix. StringRef prefix; std::pair prefixAndSym = sym.split(':'); if (!prefixAndSym.second.empty()) { sym = prefixAndSym.second; prefix = prefixAndSym.first; if (!prefix.endswith(".o") && !prefix.endswith(".o)")) { // If arch name prefix does not match arch being linked, ignore symbol. if (!ctx.archName().equals(prefix)) continue; prefix = ""; } } else sym = prefixAndSym.first; if (!sym.empty()) { ctx.appendOrderedSymbol(sym, prefix); //llvm::errs() << sym << ", prefix=" << prefix << "\n"; } } return std::error_code(); } // // There are two variants of the -filelist option: // // -filelist // In this variant, the path is to a text file which contains one file path // per line. There are no comments or trimming of whitespace. // // -fileList , // In this variant, the path is to a text file which contains a partial path // per line. The prefix is prepended to each partial path. // static std::error_code loadFileList(StringRef fileListPath, MachOLinkingContext &ctx, bool forceLoad, raw_ostream &diagnostics) { // If there is a comma, split off . std::pair opt = fileListPath.split(','); StringRef filePath = opt.first; StringRef dirName = opt.second; ctx.addInputFileDependency(filePath); // Map in file list file. ErrorOr> mb = MemoryBuffer::getFileOrSTDIN(filePath); if (std::error_code ec = mb.getError()) return ec; StringRef buffer = mb->get()->getBuffer(); while (!buffer.empty()) { // Split off each line in the file. std::pair lineAndRest = buffer.split('\n'); StringRef line = lineAndRest.first; StringRef path; if (!dirName.empty()) { // If there is a then prepend dir to each line. SmallString<256> fullPath; fullPath.assign(dirName); llvm::sys::path::append(fullPath, Twine(line)); path = ctx.copy(fullPath.str()); } else { // No use whole line as input file path. path = ctx.copy(line); } if (!ctx.pathExists(path)) { return make_dynamic_error_code(Twine("File not found '") + path + "'"); } if (ctx.testingFileUsage()) { diagnostics << "Found filelist entry " << canonicalizePath(path) << '\n'; } addFile(path, ctx, forceLoad, false, diagnostics); buffer = lineAndRest.second; } return std::error_code(); } /// Parse number assuming it is base 16, but allow 0x prefix. static bool parseNumberBase16(StringRef numStr, uint64_t &baseAddress) { if (numStr.startswith_lower("0x")) numStr = numStr.drop_front(2); return numStr.getAsInteger(16, baseAddress); } namespace lld { bool DarwinLdDriver::linkMachO(int argc, const char *argv[], raw_ostream &diagnostics) { MachOLinkingContext ctx; if (!parse(argc, argv, ctx, diagnostics)) return false; if (ctx.doNothing()) return true; return link(ctx, diagnostics); } bool DarwinLdDriver::parse(int argc, const char *argv[], MachOLinkingContext &ctx, raw_ostream &diagnostics) { // Parse command line options using DarwinLdOptions.td std::unique_ptr parsedArgs; DarwinLdOptTable table; unsigned missingIndex; unsigned missingCount; bool globalWholeArchive = false; parsedArgs.reset( table.ParseArgs(&argv[1], &argv[argc], missingIndex, missingCount)); if (missingCount) { diagnostics << "error: missing arg value for '" << parsedArgs->getArgString(missingIndex) << "' expected " << missingCount << " argument(s).\n"; return false; } for (auto unknownArg : parsedArgs->filtered(OPT_UNKNOWN)) { diagnostics << "warning: ignoring unknown argument: " << unknownArg->getAsString(*parsedArgs) << "\n"; } // Figure out output kind ( -dylib, -r, -bundle, -preload, or -static ) llvm::MachO::HeaderFileType fileType = llvm::MachO::MH_EXECUTE; if ( llvm::opt::Arg *kind = parsedArgs->getLastArg(OPT_dylib, OPT_relocatable, OPT_bundle, OPT_static, OPT_preload)) { switch (kind->getOption().getID()) { case OPT_dylib: fileType = llvm::MachO::MH_DYLIB; break; case OPT_relocatable: fileType = llvm::MachO::MH_OBJECT; break; case OPT_bundle: fileType = llvm::MachO::MH_BUNDLE; break; case OPT_static: fileType = llvm::MachO::MH_EXECUTE; break; case OPT_preload: fileType = llvm::MachO::MH_PRELOAD; break; } } // Handle -arch xxx MachOLinkingContext::Arch arch = MachOLinkingContext::arch_unknown; if (llvm::opt::Arg *archStr = parsedArgs->getLastArg(OPT_arch)) { arch = MachOLinkingContext::archFromName(archStr->getValue()); if (arch == MachOLinkingContext::arch_unknown) { diagnostics << "error: unknown arch named '" << archStr->getValue() << "'\n"; return false; } } // If no -arch specified, scan input files to find first non-fat .o file. if (arch == MachOLinkingContext::arch_unknown) { for (auto &inFile: parsedArgs->filtered(OPT_INPUT)) { // This is expensive because it opens and maps the file. But that is // ok because no -arch is rare. if (MachOLinkingContext::isThinObjectFile(inFile->getValue(), arch)) break; } if (arch == MachOLinkingContext::arch_unknown && !parsedArgs->getLastArg(OPT_test_file_usage)) { // If no -arch and no options at all, print usage message. if (parsedArgs->size() == 0) table.PrintHelp(llvm::outs(), argv[0], "LLVM Linker", false); else diagnostics << "error: -arch not specified and could not be inferred\n"; return false; } } // Handle -macosx_version_min or -ios_version_min MachOLinkingContext::OS os = MachOLinkingContext::OS::macOSX; uint32_t minOSVersion = 0; if (llvm::opt::Arg *minOS = parsedArgs->getLastArg(OPT_macosx_version_min, OPT_ios_version_min, OPT_ios_simulator_version_min)) { switch (minOS->getOption().getID()) { case OPT_macosx_version_min: os = MachOLinkingContext::OS::macOSX; if (MachOLinkingContext::parsePackedVersion(minOS->getValue(), minOSVersion)) { diagnostics << "error: malformed macosx_version_min value\n"; return false; } break; case OPT_ios_version_min: os = MachOLinkingContext::OS::iOS; if (MachOLinkingContext::parsePackedVersion(minOS->getValue(), minOSVersion)) { diagnostics << "error: malformed ios_version_min value\n"; return false; } break; case OPT_ios_simulator_version_min: os = MachOLinkingContext::OS::iOS_simulator; if (MachOLinkingContext::parsePackedVersion(minOS->getValue(), minOSVersion)) { diagnostics << "error: malformed ios_simulator_version_min value\n"; return false; } break; } } else { // No min-os version on command line, check environment variables } // Now that there's enough information parsed in, let the linking context // set up default values. ctx.configure(fileType, arch, os, minOSVersion); // Handle -e xxx if (llvm::opt::Arg *entry = parsedArgs->getLastArg(OPT_entry)) ctx.setEntrySymbolName(entry->getValue()); // Handle -o xxx if (llvm::opt::Arg *outpath = parsedArgs->getLastArg(OPT_output)) ctx.setOutputPath(outpath->getValue()); else ctx.setOutputPath("a.out"); // Handle -image_base XXX and -seg1addr XXXX if (llvm::opt::Arg *imageBase = parsedArgs->getLastArg(OPT_image_base)) { uint64_t baseAddress; if (parseNumberBase16(imageBase->getValue(), baseAddress)) { diagnostics << "error: image_base expects a hex number\n"; return false; } else if (baseAddress < ctx.pageZeroSize()) { diagnostics << "error: image_base overlaps with __PAGEZERO\n"; return false; } else if (baseAddress % ctx.pageSize()) { diagnostics << "error: image_base must be a multiple of page size (" << llvm::format("0x%" PRIx64, ctx.pageSize()) << ")\n"; return false; } ctx.setBaseAddress(baseAddress); } // Handle -dead_strip if (parsedArgs->getLastArg(OPT_dead_strip)) ctx.setDeadStripping(true); // Handle -all_load if (parsedArgs->getLastArg(OPT_all_load)) globalWholeArchive = true; // Handle -install_name if (llvm::opt::Arg *installName = parsedArgs->getLastArg(OPT_install_name)) ctx.setInstallName(installName->getValue()); else ctx.setInstallName(ctx.outputPath()); // Handle -mark_dead_strippable_dylib if (parsedArgs->getLastArg(OPT_mark_dead_strippable_dylib)) ctx.setDeadStrippableDylib(true); // Handle -compatibility_version and -current_version if (llvm::opt::Arg *vers = parsedArgs->getLastArg(OPT_compatibility_version)) { if (ctx.outputMachOType() != llvm::MachO::MH_DYLIB) { diagnostics << "error: -compatibility_version can only be used with -dylib\n"; return false; } uint32_t parsedVers; if (MachOLinkingContext::parsePackedVersion(vers->getValue(), parsedVers)) { diagnostics << "error: -compatibility_version value is malformed\n"; return false; } ctx.setCompatibilityVersion(parsedVers); } if (llvm::opt::Arg *vers = parsedArgs->getLastArg(OPT_current_version)) { if (ctx.outputMachOType() != llvm::MachO::MH_DYLIB) { diagnostics << "-current_version can only be used with -dylib\n"; return false; } uint32_t parsedVers; if (MachOLinkingContext::parsePackedVersion(vers->getValue(), parsedVers)) { diagnostics << "error: -current_version value is malformed\n"; return false; } ctx.setCurrentVersion(parsedVers); } // Handle -bundle_loader if (llvm::opt::Arg *loader = parsedArgs->getLastArg(OPT_bundle_loader)) ctx.setBundleLoader(loader->getValue()); // Handle -sectalign segname sectname align for (auto &alignArg : parsedArgs->filtered(OPT_sectalign)) { const char* segName = alignArg->getValue(0); const char* sectName = alignArg->getValue(1); const char* alignStr = alignArg->getValue(2); if ((alignStr[0] == '0') && (alignStr[1] == 'x')) alignStr += 2; unsigned long long alignValue; if (llvm::getAsUnsignedInteger(alignStr, 16, alignValue)) { diagnostics << "error: -sectalign alignment value '" << alignStr << "' not a valid number\n"; return false; } uint8_t align2 = llvm::countTrailingZeros(alignValue); if ( (unsigned long)(1 << align2) != alignValue ) { diagnostics << "warning: alignment for '-sectalign " << segName << " " << sectName << llvm::format(" 0x%llX", alignValue) << "' is not a power of two, using " << llvm::format("0x%08X", (1 << align2)) << "\n"; } ctx.addSectionAlignment(segName, sectName, align2); } // Handle -mllvm for (auto &llvmArg : parsedArgs->filtered(OPT_mllvm)) { ctx.appendLLVMOption(llvmArg->getValue()); } // Handle -print_atoms if (parsedArgs->getLastArg(OPT_print_atoms)) ctx.setPrintAtoms(); // Handle -t (trace) option. if (parsedArgs->getLastArg(OPT_t)) ctx.setLogInputFiles(true); // Handle -demangle option. if (parsedArgs->getLastArg(OPT_demangle)) ctx.setDemangleSymbols(true); // Handle -keep_private_externs if (parsedArgs->getLastArg(OPT_keep_private_externs)) { ctx.setKeepPrivateExterns(true); if (ctx.outputMachOType() != llvm::MachO::MH_OBJECT) diagnostics << "warning: -keep_private_externs only used in -r mode\n"; } // Handle -dependency_info used by Xcode. if (llvm::opt::Arg *depInfo = parsedArgs->getLastArg(OPT_dependency_info)) { if (std::error_code ec = ctx.createDependencyFile(depInfo->getValue())) { diagnostics << "warning: " << ec.message() << ", processing '-dependency_info " << depInfo->getValue() << "'\n"; } } // In -test_file_usage mode, we'll be given an explicit list of paths that // exist. We'll also be expected to print out information about how we located // libraries and so on that the user specified, but not to actually do any // linking. if (parsedArgs->getLastArg(OPT_test_file_usage)) { ctx.setTestingFileUsage(); // With paths existing by fiat, linking is not going to end well. ctx.setDoNothing(true); // Only bother looking for an existence override if we're going to use it. for (auto existingPath : parsedArgs->filtered(OPT_path_exists)) { ctx.addExistingPathForDebug(existingPath->getValue()); } } // Register possible input file parsers. if (!ctx.doNothing()) { ctx.registry().addSupportMachOObjects(ctx); ctx.registry().addSupportArchives(ctx.logInputFiles()); ctx.registry().addSupportNativeObjects(); ctx.registry().addSupportYamlFiles(); } // Now construct the set of library search directories, following ld64's // baroque set of accumulated hacks. Mostly, the algorithm constructs // { syslibroots } x { libpaths } // // Unfortunately, there are numerous exceptions: // 1. Only absolute paths get modified by syslibroot options. // 2. If there is just 1 -syslibroot, system paths not found in it are // skipped. // 3. If the last -syslibroot is "/", all of them are ignored entirely. // 4. If { syslibroots } x path == {}, the original path is kept. std::vector sysLibRoots; for (auto syslibRoot : parsedArgs->filtered(OPT_syslibroot)) { sysLibRoots.push_back(syslibRoot->getValue()); } if (!sysLibRoots.empty()) { // Ignore all if last -syslibroot is "/". if (sysLibRoots.back() != "/") ctx.setSysLibRoots(sysLibRoots); } // Paths specified with -L come first, and are not considered system paths for // the case where there is precisely 1 -syslibroot. for (auto libPath : parsedArgs->filtered(OPT_L)) { ctx.addModifiedSearchDir(libPath->getValue()); } // Process -F directories (where to look for frameworks). for (auto fwPath : parsedArgs->filtered(OPT_F)) { ctx.addFrameworkSearchDir(fwPath->getValue()); } // -Z suppresses the standard search paths. if (!parsedArgs->hasArg(OPT_Z)) { ctx.addModifiedSearchDir("/usr/lib", true); ctx.addModifiedSearchDir("/usr/local/lib", true); ctx.addFrameworkSearchDir("/Library/Frameworks", true); ctx.addFrameworkSearchDir("/System/Library/Frameworks", true); } // Now that we've constructed the final set of search paths, print out those // search paths in verbose mode. if (parsedArgs->getLastArg(OPT_v)) { diagnostics << "Library search paths:\n"; for (auto path : ctx.searchDirs()) { diagnostics << " " << path << '\n'; } diagnostics << "Framework search paths:\n"; for (auto path : ctx.frameworkDirs()) { diagnostics << " " << path << '\n'; } } // Handle -exported_symbols_list for (auto expFile : parsedArgs->filtered(OPT_exported_symbols_list)) { if (ctx.exportMode() == MachOLinkingContext::ExportMode::blackList) { diagnostics << "error: -exported_symbols_list cannot be combined " << "with -unexported_symbol[s_list]\n"; return false; } ctx.setExportMode(MachOLinkingContext::ExportMode::whiteList); if (std::error_code ec = parseExportsList(expFile->getValue(), ctx, diagnostics)) { diagnostics << "error: " << ec.message() << ", processing '-exported_symbols_list " << expFile->getValue() << "'\n"; return false; } } // Handle -exported_symbol for (auto symbol : parsedArgs->filtered(OPT_exported_symbol)) { if (ctx.exportMode() == MachOLinkingContext::ExportMode::blackList) { diagnostics << "error: -exported_symbol cannot be combined " << "with -unexported_symbol[s_list]\n"; return false; } ctx.setExportMode(MachOLinkingContext::ExportMode::whiteList); ctx.addExportSymbol(symbol->getValue()); } // Handle -unexported_symbols_list for (auto expFile : parsedArgs->filtered(OPT_unexported_symbols_list)) { if (ctx.exportMode() == MachOLinkingContext::ExportMode::whiteList) { diagnostics << "error: -unexported_symbols_list cannot be combined " << "with -exported_symbol[s_list]\n"; return false; } ctx.setExportMode(MachOLinkingContext::ExportMode::blackList); if (std::error_code ec = parseExportsList(expFile->getValue(), ctx, diagnostics)) { diagnostics << "error: " << ec.message() << ", processing '-unexported_symbols_list " << expFile->getValue() << "'\n"; return false; } } // Handle -unexported_symbol for (auto symbol : parsedArgs->filtered(OPT_unexported_symbol)) { if (ctx.exportMode() == MachOLinkingContext::ExportMode::whiteList) { diagnostics << "error: -unexported_symbol cannot be combined " << "with -exported_symbol[s_list]\n"; return false; } ctx.setExportMode(MachOLinkingContext::ExportMode::blackList); ctx.addExportSymbol(symbol->getValue()); } // Handle obosolete -multi_module and -single_module if (llvm::opt::Arg *mod = parsedArgs->getLastArg(OPT_multi_module, OPT_single_module)) { if (mod->getOption().getID() == OPT_multi_module) { diagnostics << "warning: -multi_module is obsolete and being ignored\n"; } else { if (ctx.outputMachOType() != llvm::MachO::MH_DYLIB) { diagnostics << "warning: -single_module being ignored. " "It is only for use when producing a dylib\n"; } } } // Handle -pie or -no_pie if (llvm::opt::Arg *pie = parsedArgs->getLastArg(OPT_pie, OPT_no_pie)) { switch (ctx.outputMachOType()) { case llvm::MachO::MH_EXECUTE: switch (ctx.os()) { case MachOLinkingContext::OS::macOSX: if ((minOSVersion < 0x000A0500) && (pie->getOption().getID() == OPT_pie)) { diagnostics << "-pie can only be used when targeting " "Mac OS X 10.5 or later\n"; return false; } break; case MachOLinkingContext::OS::iOS: if ((minOSVersion < 0x00040200) && (pie->getOption().getID() == OPT_pie)) { diagnostics << "-pie can only be used when targeting " "iOS 4.2 or later\n"; return false; } break; case MachOLinkingContext::OS::iOS_simulator: if (pie->getOption().getID() == OPT_no_pie) diagnostics << "iOS simulator programs must be built PIE\n"; return false; break; case MachOLinkingContext::OS::unknown: break; } ctx.setPIE(pie->getOption().getID() == OPT_pie); break; case llvm::MachO::MH_PRELOAD: break; case llvm::MachO::MH_DYLIB: case llvm::MachO::MH_BUNDLE: diagnostics << "warning: " << pie->getSpelling() << " being ignored. " << "It is only used when linking main executables\n"; break; default: diagnostics << pie->getSpelling() << " can only used when linking main executables\n"; return false; break; } } // Handle debug info handling options: -S if (parsedArgs->hasArg(OPT_S)) ctx.setDebugInfoMode(MachOLinkingContext::DebugInfoMode::noDebugMap); // Handle -order_file for (auto orderFile : parsedArgs->filtered(OPT_order_file)) { if (std::error_code ec = parseOrderFile(orderFile->getValue(), ctx, diagnostics)) { diagnostics << "error: " << ec.message() << ", processing '-order_file " << orderFile->getValue() << "'\n"; return false; } } // Handle -rpath if (parsedArgs->hasArg(OPT_rpath)) { switch (ctx.outputMachOType()) { case llvm::MachO::MH_EXECUTE: case llvm::MachO::MH_DYLIB: case llvm::MachO::MH_BUNDLE: if (!ctx.minOS("10.5", "2.0")) { if (ctx.os() == MachOLinkingContext::OS::macOSX) { diagnostics << "error: -rpath can only be used when targeting " "OS X 10.5 or later\n"; } else { diagnostics << "error: -rpath can only be used when targeting " "iOS 2.0 or later\n"; } return false; } break; default: diagnostics << "error: -rpath can only be used when creating " "a dynamic final linked image\n"; return false; } for (auto rPath : parsedArgs->filtered(OPT_rpath)) { ctx.addRpath(rPath->getValue()); } } // Handle input files for (auto &arg : *parsedArgs) { bool upward; ErrorOr resolvedPath = StringRef(); switch (arg->getOption().getID()) { default: continue; case OPT_INPUT: addFile(arg->getValue(), ctx, globalWholeArchive, false, diagnostics); break; case OPT_upward_library: addFile(arg->getValue(), ctx, false, true, diagnostics); break; case OPT_force_load: addFile(arg->getValue(), ctx, true, false, diagnostics); break; case OPT_l: case OPT_upward_l: upward = (arg->getOption().getID() == OPT_upward_l); resolvedPath = ctx.searchLibrary(arg->getValue()); if (!resolvedPath) { diagnostics << "Unable to find library for " << arg->getSpelling() << arg->getValue() << "\n"; return false; } else if (ctx.testingFileUsage()) { diagnostics << "Found " << (upward ? "upward " : " ") << "library " << canonicalizePath(resolvedPath.get()) << '\n'; } addFile(resolvedPath.get(), ctx, globalWholeArchive, upward, diagnostics); break; case OPT_framework: case OPT_upward_framework: upward = (arg->getOption().getID() == OPT_upward_framework); resolvedPath = ctx.findPathForFramework(arg->getValue()); if (!resolvedPath) { diagnostics << "Unable to find framework for " << arg->getSpelling() << " " << arg->getValue() << "\n"; return false; } else if (ctx.testingFileUsage()) { diagnostics << "Found " << (upward ? "upward " : " ") << "framework " << canonicalizePath(resolvedPath.get()) << '\n'; } addFile(resolvedPath.get(), ctx, globalWholeArchive, upward, diagnostics); break; case OPT_filelist: if (std::error_code ec = loadFileList(arg->getValue(), ctx, globalWholeArchive, diagnostics)) { diagnostics << "error: " << ec.message() << ", processing '-filelist " << arg->getValue() << "'\n"; return false; } break; } } if (ctx.getNodes().empty()) { diagnostics << "No input files\n"; return false; } // Validate the combination of options used. return ctx.validate(diagnostics); } } // namespace lld