diff options
Diffstat (limited to 'lld/lib/Driver/DarwinLdDriver.cpp')
-rw-r--r-- | lld/lib/Driver/DarwinLdDriver.cpp | 197 |
1 files changed, 197 insertions, 0 deletions
diff --git a/lld/lib/Driver/DarwinLdDriver.cpp b/lld/lib/Driver/DarwinLdDriver.cpp new file mode 100644 index 00000000000..1dbe5dfec0d --- /dev/null +++ b/lld/lib/Driver/DarwinLdDriver.cpp @@ -0,0 +1,197 @@ +//===- 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/Driver/Driver.h" +#include "lld/ReaderWriter/MachOTargetInfo.h" +#include "../ReaderWriter/MachO/MachOFormat.hpp" + +#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/FileSystem.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Signals.h" + + +namespace { + +// Create enum with OPT_xxx values for each option in DarwinOptions.td +enum DarwinOpt { + OPT_INVALID = 0, +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, HELP, META) \ + OPT_##ID, +#include "DarwinOptions.inc" + LastOption +#undef OPTION +}; + +// Create prefix string literals used in DarwinOptions.td +#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; +#include "DarwinOptions.inc" +#undef PREFIX + +// Create table mapping all options defined in DarwinOptions.td +static const llvm::opt::OptTable::Info infoTable[] = { +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \ + HELPTEXT, METAVAR) \ + { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \ + PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS }, +#include "DarwinOptions.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)){} +}; + + +} // namespace anonymous + +namespace lld { + +bool DarwinLdDriver::linkMachO(int argc, const char *argv[], + raw_ostream &diagnostics) { + MachOTargetInfo info; + if (parse(argc, argv, info, diagnostics)) + return true; + + return link(info, diagnostics); +} + + + +bool DarwinLdDriver::parse(int argc, const char *argv[], + MachOTargetInfo &info, raw_ostream &diagnostics) { + // Parse command line options using DarwinOptions.td + std::unique_ptr<llvm::opt::InputArgList> parsedArgs; + DarwinLdOptTable table; + unsigned missingIndex; + unsigned missingCount; + 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 true; + } + + for (auto it = parsedArgs->filtered_begin(OPT_UNKNOWN), + ie = parsedArgs->filtered_end(); it != ie; ++it) { + diagnostics << "warning: ignoring unknown argument: " + << (*it)->getAsString(*parsedArgs) << "\n"; + } + + // Figure out output kind ( -dylib, -r, -bundle, -preload, or -static ) + if ( llvm::opt::Arg *kind = parsedArgs->getLastArg(OPT_dylib, OPT_relocatable, + OPT_bundle, OPT_static, OPT_preload)) { + switch (kind->getOption().getID()) { + case OPT_dylib: + info.setOutputFileType(mach_o::MH_DYLIB); + break; + case OPT_relocatable: + info.setPrintRemainingUndefines(false); + info.setAllowRemainingUndefines(true); + info.setOutputFileType(mach_o::MH_OBJECT); + break; + case OPT_bundle: + info.setOutputFileType(mach_o::MH_BUNDLE); + break; + case OPT_static: + info.setOutputFileType(mach_o::MH_EXECUTE); + break; + case OPT_preload: + info.setOutputFileType(mach_o::MH_PRELOAD); + break; + } + } + + // Handle -e xxx + if (llvm::opt::Arg *entry = parsedArgs->getLastArg(OPT_entry)) + info.setEntrySymbolName(entry->getValue()); + + // Handle -o xxx + if (llvm::opt::Arg *outpath = parsedArgs->getLastArg(OPT_output)) + info.setOutputPath(outpath->getValue()); + + // Handle -dead_strip + if (parsedArgs->getLastArg(OPT_dead_strip)) + info.setDeadStripping(true); + + // Handle -arch xxx + if (llvm::opt::Arg *archStr = parsedArgs->getLastArg(OPT_arch)) { + info.setArch(llvm::StringSwitch<MachOTargetInfo::Arch>(archStr->getValue()) + .Case("x86_64", MachOTargetInfo::arch_x86_64) + .Case("i386", MachOTargetInfo::arch_x86) + .Case("armv6", MachOTargetInfo::arch_armv6) + .Case("armv7", MachOTargetInfo::arch_armv7) + .Case("armv7s", MachOTargetInfo::arch_armv7s) + .Default(MachOTargetInfo::arch_unknown)); + } + + // Handle -macosx_version_min or -ios_version_min + 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: + if (info.setOS(MachOTargetInfo::OS::macOSX, minOS->getValue())) { + diagnostics << "error: malformed macosx_version_min value\n"; + return true; + } + break; + case OPT_ios_version_min: + if (info.setOS(MachOTargetInfo::OS::iOS, minOS->getValue())) { + diagnostics << "error: malformed ios_version_min value\n"; + return true; + } + break; + case OPT_ios_simulator_version_min: + if (info.setOS(MachOTargetInfo::OS::iOS_simulator, minOS->getValue())) { + diagnostics << "error: malformed ios_simulator_version_min value\n"; + return true; + } + break; + } + } + else { + // No min-os version on command line, check environment variables + + } + + // Handle input files + for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_INPUT), + ie = parsedArgs->filtered_end(); + it != ie; ++it) { + info.appendInputFile((*it)->getValue()); + } + + return false; +} + + +} // namespace lld + + |