[lld] r276719 - COFF: Implement /linkrepro flag.

Rafael EspĂ­ndola via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 26 05:42:32 PDT 2016


The test fails on windows:

http://lab.llvm.org:8011/builders/llvm-clang-lld-x86_64-scei-ps4-windows10pro-fast/builds/8922/steps/test/logs/stdio

I will add a REQUIRES: shell for now.

Cheers,
Rafael


On 25 July 2016 at 22:00, Peter Collingbourne via llvm-commits
<llvm-commits at lists.llvm.org> wrote:
> Author: pcc
> Date: Mon Jul 25 21:00:42 2016
> New Revision: 276719
>
> URL: http://llvm.org/viewvc/llvm-project?rev=276719&view=rev
> Log:
> COFF: Implement /linkrepro flag.
>
> This flag is implemented similarly to --reproduce in the ELF linker.
>
> This patch implements /linkrepro by moving the cpio writer and associated
> utility functions to lldCore, and using that implementation in both linkers.
>
> One COFF-specific detail is that we store the object file from which the
> resource files were created in our reproducer, rather than the resource
> files themselves. This allows the reproducer to be used on non-Windows
> systems for example.
>
> Differential Revision: https://reviews.llvm.org/D22418
>
> Added:
>     lld/trunk/include/lld/Core/Reproduce.h
>     lld/trunk/lib/Core/Reproduce.cpp
>     lld/trunk/test/COFF/linkrepro.test
> Modified:
>     lld/trunk/COFF/CMakeLists.txt
>     lld/trunk/COFF/Driver.cpp
>     lld/trunk/COFF/Driver.h
>     lld/trunk/COFF/Error.h
>     lld/trunk/COFF/InputFiles.cpp
>     lld/trunk/COFF/Options.td
>     lld/trunk/ELF/CMakeLists.txt
>     lld/trunk/ELF/Driver.cpp
>     lld/trunk/ELF/Driver.h
>     lld/trunk/ELF/DriverUtils.cpp
>     lld/trunk/ELF/InputFiles.h
>     lld/trunk/lib/Core/CMakeLists.txt
>
> Modified: lld/trunk/COFF/CMakeLists.txt
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/CMakeLists.txt?rev=276719&r1=276718&r2=276719&view=diff
> ==============================================================================
> --- lld/trunk/COFF/CMakeLists.txt (original)
> +++ lld/trunk/COFF/CMakeLists.txt Mon Jul 25 21:00:42 2016
> @@ -30,7 +30,9 @@ add_lld_library(lldCOFF
>    Option
>    Support
>
> -  LINK_LIBS ${PTHREAD_LIB}
> +  LINK_LIBS
> +  lldCore
> +  ${PTHREAD_LIB}
>    )
>
>  add_dependencies(lldCOFF COFFOptionsTableGen)
>
> Modified: lld/trunk/COFF/Driver.cpp
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Driver.cpp?rev=276719&r1=276718&r2=276719&view=diff
> ==============================================================================
> --- lld/trunk/COFF/Driver.cpp (original)
> +++ lld/trunk/COFF/Driver.cpp Mon Jul 25 21:00:42 2016
> @@ -69,6 +69,10 @@ MemoryBufferRef LinkerDriver::openFile(S
>  }
>
>  static std::unique_ptr<InputFile> createFile(MemoryBufferRef MB) {
> +  if (Driver->Cpio)
> +    Driver->Cpio->append(relativeToRoot(MB.getBufferIdentifier()),
> +                         MB.getBuffer());
> +
>    // File type is detected by contents, not by file extension.
>    file_magic Magic = identify_magic(MB.getBuffer());
>    if (Magic == file_magic::archive)
> @@ -247,6 +251,37 @@ static uint64_t getDefaultImageBase() {
>    return Config->DLL ? 0x10000000 : 0x400000;
>  }
>
> +static std::string createResponseFile(const llvm::opt::InputArgList &Args,
> +                                      ArrayRef<MemoryBufferRef> MBs,
> +                                      ArrayRef<StringRef> SearchPaths) {
> +  SmallString<0> Data;
> +  raw_svector_ostream OS(Data);
> +
> +  for (auto *Arg : Args) {
> +    switch (Arg->getOption().getID()) {
> +    case OPT_linkrepro:
> +    case OPT_INPUT:
> +    case OPT_defaultlib:
> +    case OPT_libpath:
> +      break;
> +    default:
> +      OS << stringize(Arg) << "\n";
> +    }
> +  }
> +
> +  for (StringRef Path : SearchPaths) {
> +    std::string RelPath = relativeToRoot(Path);
> +    OS << "/libpath:" << quote(RelPath) << "\n";
> +  }
> +
> +  for (MemoryBufferRef MB : MBs) {
> +    std::string InputPath = relativeToRoot(MB.getBufferIdentifier());
> +    OS << quote(InputPath) << "\n";
> +  }
> +
> +  return Data.str();
> +}
> +
>  void LinkerDriver::link(llvm::ArrayRef<const char *> ArgsArr) {
>    // If the first command line argument is "/lib", link.exe acts like lib.exe.
>    // We call our own implementation of lib.exe that understands bitcode files.
> @@ -273,6 +308,17 @@ void LinkerDriver::link(llvm::ArrayRef<c
>      return;
>    }
>
> +  if (auto *Arg = Args.getLastArg(OPT_linkrepro)) {
> +    SmallString<64> Path = StringRef(Arg->getValue());
> +    llvm::sys::path::append(Path, "repro");
> +    ErrorOr<CpioFile *> F = CpioFile::create(Path);
> +    if (F)
> +      Cpio.reset(*F);
> +    else
> +      llvm::errs() << "/linkrepro: failed to open " << Path
> +                   << ".cpio: " << F.getError().message() << '\n';
> +  }
> +
>    if (Args.filtered_begin(OPT_INPUT) == Args.filtered_end())
>      fatal("no input files");
>
> @@ -511,9 +557,16 @@ void LinkerDriver::link(llvm::ArrayRef<c
>    if (!Resources.empty()) {
>      std::unique_ptr<MemoryBuffer> MB = convertResToCOFF(Resources);
>      Symtab.addFile(createFile(MB->getMemBufferRef()));
> +
> +    MBs.push_back(MB->getMemBufferRef());
>      OwningMBs.push_back(std::move(MB)); // take ownership
>    }
>
> +  if (Cpio)
> +    Cpio->append("response.txt",
> +                 createResponseFile(Args, MBs,
> +                                    ArrayRef<StringRef>(SearchPaths).slice(1)));
> +
>    // Handle /largeaddressaware
>    if (Config->is64() || Args.hasArg(OPT_largeaddressaware))
>      Config->LargeAddressAware = true;
>
> Modified: lld/trunk/COFF/Driver.h
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Driver.h?rev=276719&r1=276718&r2=276719&view=diff
> ==============================================================================
> --- lld/trunk/COFF/Driver.h (original)
> +++ lld/trunk/COFF/Driver.h Mon Jul 25 21:00:42 2016
> @@ -13,6 +13,7 @@
>  #include "Config.h"
>  #include "SymbolTable.h"
>  #include "lld/Core/LLVM.h"
> +#include "lld/Core/Reproduce.h"
>  #include "llvm/ADT/Optional.h"
>  #include "llvm/ADT/StringRef.h"
>  #include "llvm/Object/COFF.h"
> @@ -69,6 +70,8 @@ public:
>    // Used by the resolver to parse .drectve section contents.
>    void parseDirectives(StringRef S);
>
> +  std::unique_ptr<CpioFile> Cpio; // for /linkrepro
> +
>  private:
>    llvm::BumpPtrAllocator AllocAux;
>    llvm::StringSaver Alloc;
>
> Modified: lld/trunk/COFF/Error.h
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Error.h?rev=276719&r1=276718&r2=276719&view=diff
> ==============================================================================
> --- lld/trunk/COFF/Error.h (original)
> +++ lld/trunk/COFF/Error.h Mon Jul 25 21:00:42 2016
> @@ -32,6 +32,12 @@ template <class T> T check(Expected<T> E
>    return std::move(*E);
>  }
>
> +template <class T> T check(ErrorOr<T> EO) {
> +  if (!EO)
> +    fatal(EO.getError().message());
> +  return std::move(*EO);
> +}
> +
>  } // namespace coff
>  } // namespace lld
>
>
> Modified: lld/trunk/COFF/InputFiles.cpp
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/InputFiles.cpp?rev=276719&r1=276718&r2=276719&view=diff
> ==============================================================================
> --- lld/trunk/COFF/InputFiles.cpp (original)
> +++ lld/trunk/COFF/InputFiles.cpp Mon Jul 25 21:00:42 2016
> @@ -9,6 +9,7 @@
>
>  #include "Chunks.h"
>  #include "Config.h"
> +#include "Driver.h"
>  #include "Error.h"
>  #include "InputFiles.h"
>  #include "Symbols.h"
> @@ -93,9 +94,16 @@ MemoryBufferRef ArchiveFile::getMember(c
>    // Return an empty buffer if we have already returned the same buffer.
>    if (Seen[C.getChildOffset()].test_and_set())
>      return MemoryBufferRef();
> -  return check(C.getMemoryBufferRef(),
> -               "could not get the buffer for the member defining symbol " +
> -                   Sym->getName());
> +
> +  MemoryBufferRef MB =
> +      check(C.getMemoryBufferRef(),
> +            "could not get the buffer for the member defining symbol " +
> +                Sym->getName());
> +  if (C.getParent()->isThin() && Driver->Cpio)
> +    Driver->Cpio->append(relativeToRoot(check(C.getFullName())),
> +                         MB.getBuffer());
> +
> +  return MB;
>  }
>
>  void ObjectFile::parse() {
>
> Modified: lld/trunk/COFF/Options.td
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Options.td?rev=276719&r1=276718&r2=276719&view=diff
> ==============================================================================
> --- lld/trunk/COFF/Options.td (original)
> +++ lld/trunk/COFF/Options.td Mon Jul 25 21:00:42 2016
> @@ -27,6 +27,7 @@ def failifmismatch : P<"failifmismatch",
>  def heap    : P<"heap", "Size of the heap">;
>  def implib  : P<"implib", "Import library name">;
>  def libpath : P<"libpath", "Additional library search path">;
> +def linkrepro : P<"linkrepro", "Dump linker invocation and input files for debugging">;
>  def machine : P<"machine", "Specify target platform">;
>  def merge   : P<"merge", "Combine sections">;
>  def mllvm   : P<"mllvm", "Options to pass to LLVM">;
>
> Modified: lld/trunk/ELF/CMakeLists.txt
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/CMakeLists.txt?rev=276719&r1=276718&r2=276719&view=diff
> ==============================================================================
> --- lld/trunk/ELF/CMakeLists.txt (original)
> +++ lld/trunk/ELF/CMakeLists.txt Mon Jul 25 21:00:42 2016
> @@ -44,6 +44,7 @@ add_lld_library(lldELF
>
>    LINK_LIBS
>    lldConfig
> +  lldCore
>    ${PTHREAD_LIB}
>    )
>
>
> Modified: lld/trunk/ELF/Driver.cpp
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Driver.cpp?rev=276719&r1=276718&r2=276719&view=diff
> ==============================================================================
> --- lld/trunk/ELF/Driver.cpp (original)
> +++ lld/trunk/ELF/Driver.cpp Mon Jul 25 21:00:42 2016
> @@ -269,11 +269,14 @@ void LinkerDriver::main(ArrayRef<const c
>    if (const char *Path = getReproduceOption(Args)) {
>      // Note that --reproduce is a debug option so you can ignore it
>      // if you are trying to understand the whole picture of the code.
> -    Cpio.reset(CpioFile::create(Path));
> -    if (Cpio) {
> +    ErrorOr<CpioFile *> F = CpioFile::create(Path);
> +    if (F) {
> +      Cpio.reset(*F);
>        Cpio->append("response.txt", createResponseFile(Args));
>        Cpio->append("version.txt", getVersionString());
> -    }
> +    } else
> +      error(F.getError(),
> +            Twine("--reproduce: failed to open ") + Path + ".cpio");
>    }
>
>    readConfigs(Args);
>
> Modified: lld/trunk/ELF/Driver.h
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Driver.h?rev=276719&r1=276718&r2=276719&view=diff
> ==============================================================================
> --- lld/trunk/ELF/Driver.h (original)
> +++ lld/trunk/ELF/Driver.h Mon Jul 25 21:00:42 2016
> @@ -12,6 +12,7 @@
>
>  #include "SymbolTable.h"
>  #include "lld/Core/LLVM.h"
> +#include "lld/Core/Reproduce.h"
>  #include "llvm/ADT/Optional.h"
>  #include "llvm/ADT/StringRef.h"
>  #include "llvm/ADT/StringSet.h"
> @@ -23,8 +24,6 @@ namespace elf {
>
>  extern class LinkerDriver *Driver;
>
> -class CpioFile;
> -
>  class LinkerDriver {
>  public:
>    void main(ArrayRef<const char *> Args);
> @@ -69,37 +68,11 @@ enum {
>  #undef OPTION
>  };
>
> -// This is the class to create a .cpio file for --reproduce.
> -//
> -// If "--reproduce foo" is given, we create a file "foo.cpio" and
> -// copy all input files to the archive, along with a response file
> -// to re-run the same command with the same inputs.
> -// It is useful for reporting issues to LLD developers.
> -//
> -// Cpio as a file format is a deliberate choice. It's standardized in
> -// POSIX and very easy to create. cpio command is available virtually
> -// on all Unix systems. See
> -// http://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html#tag_20_92_13_07
> -// for the format details.
> -class CpioFile {
> -public:
> -  static CpioFile *create(StringRef OutputPath);
> -  void append(StringRef Path, StringRef Data);
> -
> -private:
> -  CpioFile(std::unique_ptr<llvm::raw_fd_ostream> OS, StringRef Basename);
> -
> -  std::unique_ptr<llvm::raw_fd_ostream> OS;
> -  llvm::StringSet<> Seen;
> -  std::string Basename;
> -};
> -
>  void printHelp(const char *Argv0);
>  std::string getVersionString();
>  std::vector<uint8_t> parseHexstring(StringRef S);
>
>  std::string createResponseFile(const llvm::opt::InputArgList &Args);
> -std::string relativeToRoot(StringRef Path);
>
>  std::string findFromSearchPaths(StringRef Path);
>  std::string searchLibrary(StringRef Path);
>
> Modified: lld/trunk/ELF/DriverUtils.cpp
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/DriverUtils.cpp?rev=276719&r1=276718&r2=276719&view=diff
> ==============================================================================
> --- lld/trunk/ELF/DriverUtils.cpp (original)
> +++ lld/trunk/ELF/DriverUtils.cpp Mon Jul 25 21:00:42 2016
> @@ -16,6 +16,7 @@
>  #include "Driver.h"
>  #include "Error.h"
>  #include "lld/Config/Version.h"
> +#include "lld/Core/Reproduce.h"
>  #include "llvm/ADT/STLExtras.h"
>  #include "llvm/ADT/Triple.h"
>  #include "llvm/Option/Option.h"
> @@ -105,107 +106,6 @@ std::string elf::getVersionString() {
>    return "LLD " + Version + " " + Repo + "\n";
>  }
>
> -// Makes a given pathname an absolute path first, and then remove
> -// beginning /. For example, "../foo.o" is converted to "home/john/foo.o",
> -// assuming that the current directory is "/home/john/bar".
> -std::string elf::relativeToRoot(StringRef Path) {
> -  SmallString<128> Abs = Path;
> -  if (std::error_code EC = fs::make_absolute(Abs))
> -    fatal("make_absolute failed: " + EC.message());
> -  path::remove_dots(Abs, /*remove_dot_dot=*/true);
> -
> -  // This is Windows specific. root_name() returns a drive letter
> -  // (e.g. "c:") or a UNC name (//net). We want to keep it as part
> -  // of the result.
> -  SmallString<128> Res;
> -  StringRef Root = path::root_name(Abs);
> -  if (Root.endswith(":"))
> -    Res = Root.drop_back();
> -  else if (Root.startswith("//"))
> -    Res = Root.substr(2);
> -
> -  path::append(Res, path::relative_path(Abs));
> -  return Res.str();
> -}
> -
> -CpioFile::CpioFile(std::unique_ptr<raw_fd_ostream> OS, StringRef S)
> -    : OS(std::move(OS)), Basename(S) {}
> -
> -CpioFile *CpioFile::create(StringRef OutputPath) {
> -  std::string Path = (OutputPath + ".cpio").str();
> -  std::error_code EC;
> -  auto OS = llvm::make_unique<raw_fd_ostream>(Path, EC, fs::F_None);
> -  if (EC) {
> -    error(EC, "--reproduce: failed to open " + Path);
> -    return nullptr;
> -  }
> -  return new CpioFile(std::move(OS), path::filename(OutputPath));
> -}
> -
> -static void writeMember(raw_fd_ostream &OS, StringRef Path, StringRef Data) {
> -  // The c_dev/c_ino pair should be unique according to the spec,
> -  // but no one seems to care.
> -  OS << "070707";                        // c_magic
> -  OS << "000000";                        // c_dev
> -  OS << "000000";                        // c_ino
> -  OS << "100664";                        // c_mode: C_ISREG | rw-rw-r--
> -  OS << "000000";                        // c_uid
> -  OS << "000000";                        // c_gid
> -  OS << "000001";                        // c_nlink
> -  OS << "000000";                        // c_rdev
> -  OS << "00000000000";                   // c_mtime
> -  OS << format("%06o", Path.size() + 1); // c_namesize
> -  OS << format("%011o", Data.size());    // c_filesize
> -  OS << Path << '\0';                    // c_name
> -  OS << Data;                            // c_filedata
> -}
> -
> -void CpioFile::append(StringRef Path, StringRef Data) {
> -  if (!Seen.insert(Path).second)
> -    return;
> -
> -  // Construct an in-archive filename so that /home/foo/bar is stored
> -  // as baz/home/foo/bar where baz is the basename of the output file.
> -  // (i.e. in that case we are creating baz.cpio.)
> -  SmallString<128> Fullpath;
> -  path::append(Fullpath, Basename, Path);
> -
> -  // Use unix path separators so the cpio can be extracted on both unix and
> -  // windows.
> -  std::replace(Fullpath.begin(), Fullpath.end(), '\\', '/');
> -
> -  writeMember(*OS, Fullpath, Data);
> -
> -  // Print the trailer and seek back.
> -  // This way we have a valid archive if we crash.
> -  uint64_t Pos = OS->tell();
> -  writeMember(*OS, "TRAILER!!!", "");
> -  OS->seek(Pos);
> -}
> -
> -// Quote a given string if it contains a space character.
> -static std::string quote(StringRef S) {
> -  if (S.find(' ') == StringRef::npos)
> -    return S;
> -  return ("\"" + S + "\"").str();
> -}
> -
> -static std::string rewritePath(StringRef S) {
> -  if (fs::exists(S))
> -    return relativeToRoot(S);
> -  return S;
> -}
> -
> -static std::string stringize(opt::Arg *Arg) {
> -  std::string K = Arg->getSpelling();
> -  if (Arg->getNumValues() == 0)
> -    return K;
> -  std::string V = quote(Arg->getValue());
> -  if (Arg->getOption().getRenderStyle() == opt::Option::RenderJoinedStyle)
> -    return K + V;
> -  return K + " " + V;
> -}
> -
>  // Reconstructs command line arguments so that so that you can re-run
>  // the same command with the same inputs. This is for --reproduce.
>  std::string elf::createResponseFile(const opt::InputArgList &Args) {
> @@ -226,8 +126,8 @@ std::string elf::createResponseFile(cons
>      case OPT_alias_script_T:
>      case OPT_script:
>      case OPT_version_script:
> -      OS << Arg->getSpelling() << " "
> -         << quote(rewritePath(Arg->getValue())) << "\n";
> +      OS << Arg->getSpelling() << " " << quote(rewritePath(Arg->getValue()))
> +         << "\n";
>        break;
>      default:
>        OS << stringize(Arg) << "\n";
>
> Modified: lld/trunk/ELF/InputFiles.h
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputFiles.h?rev=276719&r1=276718&r2=276719&view=diff
> ==============================================================================
> --- lld/trunk/ELF/InputFiles.h (original)
> +++ lld/trunk/ELF/InputFiles.h Mon Jul 25 21:00:42 2016
> @@ -16,6 +16,7 @@
>  #include "Symbols.h"
>
>  #include "lld/Core/LLVM.h"
> +#include "lld/Core/Reproduce.h"
>  #include "llvm/ADT/DenseSet.h"
>  #include "llvm/ADT/STLExtras.h"
>  #include "llvm/IR/Comdat.h"
>
> Added: lld/trunk/include/lld/Core/Reproduce.h
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/Core/Reproduce.h?rev=276719&view=auto
> ==============================================================================
> --- lld/trunk/include/lld/Core/Reproduce.h (added)
> +++ lld/trunk/include/lld/Core/Reproduce.h Mon Jul 25 21:00:42 2016
> @@ -0,0 +1,70 @@
> +//===- Reproduce.h - Utilities for creating reproducers ---------*- C++ -*-===//
> +//
> +//                             The LLVM Linker
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef LLD_CORE_REPRODUCE_H
> +#define LLD_CORE_REPRODUCE_H
> +
> +#include "lld/Core/LLVM.h"
> +#include "llvm/ADT/StringRef.h"
> +#include "llvm/ADT/StringSet.h"
> +#include "llvm/Support/Error.h"
> +
> +namespace llvm {
> +
> +class raw_fd_ostream;
> +
> +namespace opt { class Arg; }
> +
> +}
> +
> +namespace lld {
> +
> +// This class creates a .cpio file for --reproduce (ELF) or /linkrepro (COFF).
> +//
> +// If "--reproduce foo" is given, we create a file "foo.cpio" and
> +// copy all input files to the archive, along with a response file
> +// to re-run the same command with the same inputs.
> +// It is useful for reporting issues to LLD developers.
> +//
> +// Cpio as a file format is a deliberate choice. It's standardized in
> +// POSIX and very easy to create. cpio command is available virtually
> +// on all Unix systems. See
> +// http://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html#tag_20_92_13_07
> +// for the format details.
> +class CpioFile {
> +public:
> +  static ErrorOr<CpioFile *> create(StringRef OutputPath);
> +  void append(StringRef Path, StringRef Data);
> +
> +private:
> +  CpioFile(std::unique_ptr<llvm::raw_fd_ostream> OS, StringRef Basename);
> +
> +  std::unique_ptr<llvm::raw_fd_ostream> OS;
> +  llvm::StringSet<> Seen;
> +  std::string Basename;
> +};
> +
> +// Makes a given pathname an absolute path first, and then remove
> +// beginning /. For example, "../foo.o" is converted to "home/john/foo.o",
> +// assuming that the current directory is "/home/john/bar".
> +std::string relativeToRoot(StringRef Path);
> +
> +// Quote a given string if it contains a space character.
> +std::string quote(StringRef S);
> +
> +// Rewrite the given path if a file exists with that pathname, otherwise
> +// returns the original path.
> +std::string rewritePath(StringRef S);
> +
> +// Returns the string form of the given argument.
> +std::string stringize(llvm::opt::Arg *Arg);
> +
> +}
> +
> +#endif
>
> Modified: lld/trunk/lib/Core/CMakeLists.txt
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Core/CMakeLists.txt?rev=276719&r1=276718&r2=276719&view=diff
> ==============================================================================
> --- lld/trunk/lib/Core/CMakeLists.txt (original)
> +++ lld/trunk/lib/Core/CMakeLists.txt Mon Jul 25 21:00:42 2016
> @@ -4,6 +4,7 @@ add_lld_library(lldCore
>    File.cpp
>    LinkingContext.cpp
>    Reader.cpp
> +  Reproduce.cpp
>    Resolver.cpp
>    SymbolTable.cpp
>    Writer.cpp
>
> Added: lld/trunk/lib/Core/Reproduce.cpp
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Core/Reproduce.cpp?rev=276719&view=auto
> ==============================================================================
> --- lld/trunk/lib/Core/Reproduce.cpp (added)
> +++ lld/trunk/lib/Core/Reproduce.cpp Mon Jul 25 21:00:42 2016
> @@ -0,0 +1,121 @@
> +//===- Reproduce.cpp - Utilities for creating reproducers -----------------===//
> +//
> +//                             The LLVM Linker
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +
> +#include "lld/Core/Reproduce.h"
> +#include "llvm/ADT/STLExtras.h"
> +#include "llvm/ADT/Twine.h"
> +#include "llvm/Option/Arg.h"
> +#include "llvm/Support/Error.h"
> +#include "llvm/Support/FileSystem.h"
> +#include "llvm/Support/Format.h"
> +#include "llvm/Support/Path.h"
> +
> +using namespace lld;
> +using namespace llvm;
> +using namespace sys;
> +
> +CpioFile::CpioFile(std::unique_ptr<raw_fd_ostream> OS, StringRef S)
> +    : OS(std::move(OS)), Basename(S) {}
> +
> +ErrorOr<CpioFile *> CpioFile::create(StringRef OutputPath) {
> +  std::string Path = (OutputPath + ".cpio").str();
> +  std::error_code EC;
> +  auto OS = make_unique<raw_fd_ostream>(Path, EC, sys::fs::F_None);
> +  if (EC)
> +    return EC;
> +  return new CpioFile(std::move(OS), path::filename(OutputPath));
> +}
> +
> +static void writeMember(raw_fd_ostream &OS, StringRef Path, StringRef Data) {
> +  // The c_dev/c_ino pair should be unique according to the spec,
> +  // but no one seems to care.
> +  OS << "070707";                        // c_magic
> +  OS << "000000";                        // c_dev
> +  OS << "000000";                        // c_ino
> +  OS << "100664";                        // c_mode: C_ISREG | rw-rw-r--
> +  OS << "000000";                        // c_uid
> +  OS << "000000";                        // c_gid
> +  OS << "000001";                        // c_nlink
> +  OS << "000000";                        // c_rdev
> +  OS << "00000000000";                   // c_mtime
> +  OS << format("%06o", Path.size() + 1); // c_namesize
> +  OS << format("%011o", Data.size());    // c_filesize
> +  OS << Path << '\0';                    // c_name
> +  OS << Data;                            // c_filedata
> +}
> +
> +void CpioFile::append(StringRef Path, StringRef Data) {
> +  if (!Seen.insert(Path).second)
> +    return;
> +
> +  // Construct an in-archive filename so that /home/foo/bar is stored
> +  // as baz/home/foo/bar where baz is the basename of the output file.
> +  // (i.e. in that case we are creating baz.cpio.)
> +  SmallString<128> Fullpath;
> +  path::append(Fullpath, Basename, Path);
> +
> +  // Use unix path separators so the cpio can be extracted on both unix and
> +  // windows.
> +  std::replace(Fullpath.begin(), Fullpath.end(), '\\', '/');
> +
> +  writeMember(*OS, Fullpath, Data);
> +
> +  // Print the trailer and seek back.
> +  // This way we have a valid archive if we crash.
> +  uint64_t Pos = OS->tell();
> +  writeMember(*OS, "TRAILER!!!", "");
> +  OS->seek(Pos);
> +}
> +
> +// Makes a given pathname an absolute path first, and then remove
> +// beginning /. For example, "../foo.o" is converted to "home/john/foo.o",
> +// assuming that the current directory is "/home/john/bar".
> +std::string lld::relativeToRoot(StringRef Path) {
> +  SmallString<128> Abs = Path;
> +  if (sys::fs::make_absolute(Abs))
> +    return Path;
> +  path::remove_dots(Abs, /*remove_dot_dot=*/true);
> +
> +  // This is Windows specific. root_name() returns a drive letter
> +  // (e.g. "c:") or a UNC name (//net). We want to keep it as part
> +  // of the result.
> +  SmallString<128> Res;
> +  StringRef Root = path::root_name(Abs);
> +  if (Root.endswith(":"))
> +    Res = Root.drop_back();
> +  else if (Root.startswith("//"))
> +    Res = Root.substr(2);
> +
> +  path::append(Res, path::relative_path(Abs));
> +
> +  return Res.str();
> +}
> +
> +// Quote a given string if it contains a space character.
> +std::string lld::quote(StringRef S) {
> +  if (S.find(' ') == StringRef::npos)
> +    return S;
> +  return ("\"" + S + "\"").str();
> +}
> +
> +std::string lld::rewritePath(StringRef S) {
> +  if (fs::exists(S))
> +    return relativeToRoot(S);
> +  return S;
> +}
> +
> +std::string lld::stringize(opt::Arg *Arg) {
> +  std::string K = Arg->getSpelling();
> +  if (Arg->getNumValues() == 0)
> +    return K;
> +  std::string V = quote(Arg->getValue());
> +  if (Arg->getOption().getRenderStyle() == opt::Option::RenderJoinedStyle)
> +    return K + V;
> +  return K + " " + V;
> +}
>
> Added: lld/trunk/test/COFF/linkrepro.test
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/linkrepro.test?rev=276719&view=auto
> ==============================================================================
> --- lld/trunk/test/COFF/linkrepro.test (added)
> +++ lld/trunk/test/COFF/linkrepro.test Mon Jul 25 21:00:42 2016
> @@ -0,0 +1,35 @@
> +# RUN: rm -rf %t.dir
> +# RUN: mkdir -p %t.dir/build1 %t.dir/build2 %t.dir/build3
> +# RUN: yaml2obj < %p/Inputs/hello32.yaml > %t.obj
> +
> +# RUN: cd %t.dir/build1
> +# RUN: lld-link %t.obj %p/Inputs/std32.lib /subsystem:console \
> +# RUN:   /entry:main at 0 /linkrepro:. /out:%t.exe
> +# RUN: cpio -id < repro.cpio
> +# RUN: diff %t.obj repro/%:t.obj
> +# RUN: diff %p/Inputs/std32.lib repro/%:p/Inputs/std32.lib
> +# RUN: FileCheck %s --check-prefix=RSP < repro/response.txt
> +
> +# RUN: cd %t.dir/build2
> +# RUN: lld-link %t.obj /libpath:%p/Inputs /defaultlib:std32 /subsystem:console \
> +# RUN:   /entry:main at 0 /linkrepro:. /out:%t.exe
> +# RUN: cpio -id < repro.cpio
> +# RUN: diff %t.obj repro/%:t.obj
> +# RUN: diff %p/Inputs/std32.lib repro/%:p/Inputs/std32.lib
> +# RUN: FileCheck %s --check-prefix=RSP < repro/response.txt
> +
> +# RUN: cd %t.dir/build3
> +# RUN: env LIB=%p/Inputs lld-link %t.obj /defaultlib:std32 /subsystem:console \
> +# RUN:   /entry:main at 0 /linkrepro:. /out:%t.exe
> +# RUN: cpio -id < repro.cpio
> +# RUN: diff %t.obj repro/%:t.obj
> +# RUN: diff %p/Inputs/std32.lib repro/%:p/Inputs/std32.lib
> +# RUN: FileCheck %s --check-prefix=RSP < repro/response.txt
> +
> +# RSP: /subsystem:console
> +# RSP: /entry:main at 0
> +# RSP-NOT: /linkrepro:
> +# RSP: /out:
> +# RSP: linkrepro.test.tmp.obj
> +# RSP-NOT: defaultlib
> +# RSP: std32.lib
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits


More information about the llvm-commits mailing list