Beispiel #1
0
void Driver::parseLLVMOptions(const LinkingContext &ctx) {
  // Honor -mllvm
  if (!ctx.llvmOptions().empty()) {
    unsigned numArgs = ctx.llvmOptions().size();
    auto **args = new const char *[numArgs + 2];
    args[0] = "lld (LLVM option parsing)";
    for (unsigned i = 0; i != numArgs; ++i)
      args[i + 1] = ctx.llvmOptions()[i];
    args[numArgs + 1] = nullptr;
    llvm::cl::ParseCommandLineOptions(numArgs + 1, args);
  }
}
Beispiel #2
0
/// This is where the link is actually performed.
bool Driver::link(LinkingContext &ctx, raw_ostream &diagnostics) {
  // Honor -mllvm
  if (!ctx.llvmOptions().empty()) {
    unsigned numArgs = ctx.llvmOptions().size();
    const char **args = new const char *[numArgs + 2];
    args[0] = "lld (LLVM option parsing)";
    for (unsigned i = 0; i != numArgs; ++i)
      args[i + 1] = ctx.llvmOptions()[i];
    args[numArgs + 1] = 0;
    llvm::cl::ParseCommandLineOptions(numArgs + 1, args);
  }
  if (ctx.getNodes().empty())
    return false;

  for (std::unique_ptr<Node> &ie : ctx.getNodes())
    if (FileNode *node = dyn_cast<FileNode>(ie.get()))
      ctx.getTaskGroup().spawn([node] { node->getFile()->parse(); });

  std::vector<std::unique_ptr<File>> internalFiles;
  ctx.createInternalFiles(internalFiles);
  for (auto i = internalFiles.rbegin(), e = internalFiles.rend(); i != e; ++i) {
    auto &members = ctx.getNodes();
    members.insert(members.begin(), llvm::make_unique<FileNode>(std::move(*i)));
  }

  // Give target a chance to add files.
  std::vector<std::unique_ptr<File>> implicitFiles;
  ctx.createImplicitFiles(implicitFiles);
  for (auto i = implicitFiles.rbegin(), e = implicitFiles.rend(); i != e; ++i) {
    auto &members = ctx.getNodes();
    members.insert(members.begin(), llvm::make_unique<FileNode>(std::move(*i)));
  }

  // Give target a chance to postprocess input files.
  // Mach-O uses this chance to move all object files before library files.
  // ELF adds specific undefined symbols resolver.
  ctx.finalizeInputFiles();

  // Do core linking.
  ScopedTask resolveTask(getDefaultDomain(), "Resolve");
  Resolver resolver(ctx);
  if (!resolver.resolve()) {
    ctx.getTaskGroup().sync();
    return false;
  }
  std::unique_ptr<SimpleFile> merged = resolver.resultFile();
  resolveTask.end();

  // Run passes on linked atoms.
  ScopedTask passTask(getDefaultDomain(), "Passes");
  PassManager pm;
  ctx.addPasses(pm);
  pm.runOnFile(merged);
  passTask.end();

  // Give linked atoms to Writer to generate output file.
  ScopedTask writeTask(getDefaultDomain(), "Write");
  if (std::error_code ec = ctx.writeFile(*merged)) {
    diagnostics << "Failed to write file '" << ctx.outputPath()
                << "': " << ec.message() << "\n";
    return false;
  }

  return true;
}
Beispiel #3
0
/// This is where the link is actually performed.
bool Driver::link(const LinkingContext &context, raw_ostream &diagnostics) {
  // Honor -mllvm
  if (!context.llvmOptions().empty()) {
    unsigned numArgs = context.llvmOptions().size();
    const char **args = new const char *[numArgs + 2];
    args[0] = "lld (LLVM option parsing)";
    for (unsigned i = 0; i != numArgs; ++i)
      args[i + 1] = context.llvmOptions()[i];
    args[numArgs + 1] = 0;
    llvm::cl::ParseCommandLineOptions(numArgs + 1, args);
  }
  InputGraph &inputGraph = context.inputGraph();
  if (!inputGraph.numFiles())
    return false;

  // Read inputs
  ScopedTask readTask(getDefaultDomain(), "Read Args");
  std::vector<std::vector<std::unique_ptr<File> > > files(
      inputGraph.numFiles());
  size_t index = 0;
  std::atomic<bool> fail(false);
  TaskGroup tg;
  std::vector<std::unique_ptr<LinkerInput> > linkerInputs;
  for (auto &ie : inputGraph.inputElements()) {
    if (ie->kind() == InputElement::Kind::File) {
      FileNode *fileNode = (llvm::dyn_cast<FileNode>)(ie.get());
      auto linkerInput = fileNode->createLinkerInput(context);
      if (!linkerInput) {
        llvm::outs() << fileNode->errStr(error_code(linkerInput)) << "\n";
        return false;
      }
      linkerInputs.push_back(std::move(*linkerInput));
    }
    else {
      llvm_unreachable("Not handling other types of InputElements");
    }
  }
  for (const auto &input : linkerInputs) {
    if (context.logInputFiles())
      llvm::outs() << input->getUserPath() << "\n";

    tg.spawn([ &, index]{
      if (error_code ec = context.parseFile(*input, files[index])) {
        diagnostics << "Failed to read file: " << input->getUserPath() << ": "
                    << ec.message() << "\n";
        fail = true;
        return;
      }
    });
    ++index;
  }
  tg.sync();
  readTask.end();

  if (fail)
    return false;

  InputFiles inputs;

  for (auto &f : inputGraph.internalFiles())
    inputs.appendFile(*f.get());

  for (auto &f : files)
    inputs.appendFiles(f);

  // Give target a chance to add files.
  context.addImplicitFiles(inputs);

  // assign an ordinal to each file so sort() can preserve command line order
  inputs.assignFileOrdinals();

  // Do core linking.
  ScopedTask resolveTask(getDefaultDomain(), "Resolve");
  Resolver resolver(context, inputs);
  if (resolver.resolve()) {
    if (!context.allowRemainingUndefines())
      return false;
  }
  MutableFile &merged = resolver.resultFile();
  resolveTask.end();

  // Run passes on linked atoms.
  ScopedTask passTask(getDefaultDomain(), "Passes");
  PassManager pm;
  context.addPasses(pm);
  pm.runOnFile(merged);
  passTask.end();

  // Give linked atoms to Writer to generate output file.
  ScopedTask writeTask(getDefaultDomain(), "Write");
  if (error_code ec = context.writeFile(merged)) {
    diagnostics << "Failed to write file '" << context.outputPath()
                << "': " << ec.message() << "\n";
    return false;
  }

  return true;
}