<div dir="ltr">I'm not sure we want to add this dependency on cpio. Maybe we can make it optional by checking for it on PATH in lit.cfg?</div><div class="gmail_extra"><br><div class="gmail_quote">On Tue, May 3, 2016 at 10:30 AM, Rafael Espindola via llvm-commits <span dir="ltr"><<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: rafael<br>
Date: Tue May 3 12:30:44 2016<br>
New Revision: 268404<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=268404&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=268404&view=rev</a><br>
Log:<br>
Produce cpio files for --reproduce.<br>
<br>
We want --reproduce to<br>
<br>
* not rewrite scripts and thin archives<br>
* work with absolute paths<br>
<br>
Given that, it pretty much has to create a full directory tree. On windows that<br>
is problematic because of the very short maximum path limit. On most cases<br>
users can still work around it with "--repro c:\r", but that is annoying and<br>
not viable for automated testing.<br>
<br>
We then need to produce some form of archive with the files. The first option<br>
that comes to mind is .a files since we already have code for writing them.<br>
There are a few problems with them<br>
<br>
The format has a dedicated string table, so we cannot start writing it until<br>
all members are known.<br>
Regular implementations don't support creating directories. We could make<br>
llvm-ar support that, but that is probably not a good idea.<br>
The next natural option would be tar. The problem is that to support long path<br>
names (which is how this started) it needs a "pax extended header" making this<br>
an annoying format to write.<br>
<br>
The next option I looked at seems a natural fit: cpio files.<br>
<br>
They are available on pretty much every unix, support directories and long path<br>
names and are really easy to write. The only slightly annoying part is a<br>
terminator, but at least gnu cpio only prints a warning if it is missing, which<br>
is handy for crashes. This patch still makes an effort to always create it.<br>
<br>
Added:<br>
lld/trunk/test/ELF/reproduce-error.s<br>
lld/trunk/test/ELF/reproduce-windows.s<br>
Modified:<br>
lld/trunk/ELF/Driver.cpp<br>
lld/trunk/ELF/Driver.h<br>
lld/trunk/ELF/DriverUtils.cpp<br>
lld/trunk/ELF/Error.cpp<br>
lld/trunk/ELF/Error.h<br>
lld/trunk/ELF/InputFiles.cpp<br>
lld/trunk/test/ELF/reproduce-linkerscript.s<br>
lld/trunk/test/ELF/reproduce-thin-archive.s<br>
lld/trunk/test/ELF/reproduce.s<br>
<br>
Modified: lld/trunk/ELF/Driver.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Driver.cpp?rev=268404&r1=268403&r2=268404&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Driver.cpp?rev=268404&r1=268403&r2=268404&view=diff</a><br>
==============================================================================<br>
--- lld/trunk/ELF/Driver.cpp (original)<br>
+++ lld/trunk/ELF/Driver.cpp Tue May 3 12:30:44 2016<br>
@@ -108,14 +108,14 @@ void LinkerDriver::addFile(StringRef Pat<br>
using namespace sys::fs;<br>
if (Config->Verbose)<br>
outs() << Path << "\n";<br>
- if (!Config->Reproduce.empty())<br>
- copyInputFile(Path);<br>
<br>
Optional<MemoryBufferRef> Buffer = readFile(Path);<br>
if (!Buffer.hasValue())<br>
return;<br>
MemoryBufferRef MBRef = *Buffer;<br>
<br>
+ maybeCopyInputFile(Path, MBRef.getBuffer());<br>
+<br>
switch (identify_magic(MBRef.getBuffer())) {<br>
case file_magic::unknown:<br>
readLinkerScript(MBRef);<br>
@@ -252,8 +252,13 @@ void LinkerDriver::main(ArrayRef<const c<br>
readConfigs(Args);<br>
initLLVM(Args);<br>
<br>
- if (!Config->Reproduce.empty())<br>
+ if (!Config->Reproduce.empty()) {<br>
+ std::error_code EC;<br>
+ ReproduceArchive = llvm::make_unique<raw_fd_ostream>(<br>
+ Config->Reproduce + ".cpio", EC, fs::F_None);<br>
+ check(EC);<br>
createResponseFile(Args);<br>
+ }<br>
<br>
createFiles(Args);<br>
checkOptions(Args);<br>
@@ -486,6 +491,8 @@ template <class ELFT> void LinkerDriver:<br>
for (auto *Arg : Args.filtered(OPT_wrap))<br>
Symtab.wrap(Arg->getValue());<br>
<br>
+ maybeCloseReproArchive();<br>
+<br>
// Write the result to the file.<br>
if (Config->GcSections)<br>
markLive<ELFT>();<br>
<br>
Modified: lld/trunk/ELF/Driver.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Driver.h?rev=268404&r1=268403&r2=268404&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Driver.h?rev=268404&r1=268403&r2=268404&view=diff</a><br>
==============================================================================<br>
--- lld/trunk/ELF/Driver.h (original)<br>
+++ lld/trunk/ELF/Driver.h Tue May 3 12:30:44 2016<br>
@@ -14,6 +14,7 @@<br>
#include "lld/Core/LLVM.h"<br>
#include "llvm/ADT/Optional.h"<br>
#include "llvm/ADT/StringRef.h"<br>
+#include "llvm/ADT/StringSet.h"<br>
#include "llvm/Option/ArgList.h"<br>
#include "llvm/Support/raw_ostream.h"<br>
<br>
@@ -29,6 +30,10 @@ public:<br>
void addLibrary(StringRef Name);<br>
llvm::LLVMContext Context;<br>
<br>
+ // for --reproduce<br>
+ std::unique_ptr<llvm::raw_fd_ostream> ReproduceArchive;<br>
+ llvm::StringSet<> IncludedFiles;<br>
+<br>
private:<br>
std::vector<MemoryBufferRef> getArchiveMembers(MemoryBufferRef MB);<br>
llvm::Optional<MemoryBufferRef> readFile(StringRef Path);<br>
@@ -69,7 +74,7 @@ void printHelp(const char *Argv0);<br>
void printVersion();<br>
<br>
void createResponseFile(const llvm::opt::InputArgList &Args);<br>
-void copyInputFile(StringRef Path);<br>
+void maybeCopyInputFile(StringRef Path, StringRef Buffer);<br>
<br>
std::string findFromSearchPaths(StringRef Path);<br>
std::string searchLibrary(StringRef Path);<br>
<br>
Modified: lld/trunk/ELF/DriverUtils.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/DriverUtils.cpp?rev=268404&r1=268403&r2=268404&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/DriverUtils.cpp?rev=268404&r1=268403&r2=268404&view=diff</a><br>
==============================================================================<br>
--- lld/trunk/ELF/DriverUtils.cpp (original)<br>
+++ lld/trunk/ELF/DriverUtils.cpp Tue May 3 12:30:44 2016<br>
@@ -113,20 +113,48 @@ static std::string relativeToRoot(String<br>
static std::string getDestPath(StringRef Path) {<br>
std::string Relpath = relativeToRoot(Path);<br>
SmallString<128> Dest;<br>
- path::append(Dest, Config->Reproduce, Relpath);<br>
+ path::append(Dest, path::filename(Config->Reproduce), Relpath);<br>
return Dest.str();<br>
}<br>
<br>
-// Copies file Src to {Config->Reproduce}/Src.<br>
-void elf::copyInputFile(StringRef Src) {<br>
+static void maybePrintCpioMember(StringRef Path, StringRef Data) {<br>
+ if (Config->Reproduce.empty())<br>
+ return;<br>
+<br>
+ if (!Driver->IncludedFiles.insert(Path).second)<br>
+ return;<br>
+<br>
+ raw_fd_ostream &OS = *Driver->ReproduceArchive;<br>
+ OS << "070707"; // c_magic<br>
+<br>
+ // The c_dev/c_ino pair should be unique according to the spec, but no one<br>
+ // seems to care.<br>
+ OS << "000000"; // c_dev<br>
+ OS << "000000"; // c_ino<br>
+<br>
+ OS << "100664"; // c_mode: C_ISREG | rw-rw-r--<br>
+ OS << "000000"; // c_uid<br>
+ OS << "000000"; // c_gid<br>
+ OS << "000001"; // c_nlink<br>
+ OS << "000000"; // c_rdev<br>
+ OS << "00000000000"; // c_mtime<br>
+ OS << format("%06o", Path.size() + 1); // c_namesize<br>
+ OS << format("%011o", Data.size()); // c_filesize<br>
+ OS << Path << '\0'; // c_name<br>
+ OS << Data; // c_filedata<br>
+}<br>
+<br>
+// Write file Src with content Data to the archive.<br>
+void elf::maybeCopyInputFile(StringRef Src, StringRef Data) {<br>
std::string Dest = getDestPath(Src);<br>
- StringRef Dir = path::parent_path(Dest);<br>
- if (std::error_code EC = fs::create_directories(Dir)) {<br>
- error(EC, Dir + ": can't create directory");<br>
+ maybePrintCpioMember(Dest, Data);<br>
+}<br>
+<br>
+void elf::maybeCloseReproArchive() {<br>
+ if (!Driver->ReproduceArchive)<br>
return;<br>
- }<br>
- if (std::error_code EC = fs::copy_file(Src, Dest))<br>
- error(EC, "failed to copy file: " + Dest);<br>
+ maybePrintCpioMember("TRAILER!!!", "");<br>
+ Driver->ReproduceArchive.reset();<br>
}<br>
<br>
// Quote a given string if it contains a space character.<br>
@@ -148,20 +176,8 @@ static std::string rewritePath(StringRef<br>
// "ld.lld @response.txt". Used by --reproduce. This feature is<br>
// supposed to be used by users to report an issue to LLD developers.<br>
void elf::createResponseFile(const opt::InputArgList &Args) {<br>
- // Create the output directory.<br>
- if (std::error_code EC =<br>
- fs::create_directories(Config->Reproduce, /*IgnoreExisting=*/false)) {<br>
- error(EC, Config->Reproduce + ": can't create directory");<br>
- return;<br>
- }<br>
-<br>
- // Open "response.txt".<br>
- SmallString<128> Path;<br>
- path::append(Path, Config->Reproduce, "response.txt");<br>
- std::error_code EC;<br>
- raw_fd_ostream OS(Path, EC, fs::OpenFlags::F_None);<br>
- check(EC);<br>
-<br>
+ SmallString<0> Data;<br>
+ raw_svector_ostream OS(Data);<br>
// Copy the command line to response.txt while rewriting paths.<br>
for (auto *Arg : Args) {<br>
switch (Arg->getOption().getID()) {<br>
@@ -185,6 +201,10 @@ void elf::createResponseFile(const opt::<br>
OS << "\n";<br>
}<br>
}<br>
+<br>
+ SmallString<128> Dest;<br>
+ path::append(Dest, path::filename(Config->Reproduce), "response.txt");<br>
+ maybePrintCpioMember(Dest, Data);<br>
}<br>
<br>
std::string elf::findFromSearchPaths(StringRef Path) {<br>
<br>
Modified: lld/trunk/ELF/Error.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Error.cpp?rev=268404&r1=268403&r2=268404&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Error.cpp?rev=268404&r1=268403&r2=268404&view=diff</a><br>
==============================================================================<br>
--- lld/trunk/ELF/Error.cpp (original)<br>
+++ lld/trunk/ELF/Error.cpp Tue May 3 12:30:44 2016<br>
@@ -29,6 +29,7 @@ void warning(const Twine &Msg) { llvm::e<br>
void error(const Twine &Msg) {<br>
*ErrorOS << Msg << "\n";<br>
HasError = true;<br>
+ maybeCloseReproArchive();<br>
}<br>
<br>
void error(std::error_code EC, const Twine &Prefix) {<br>
@@ -38,6 +39,7 @@ void error(std::error_code EC, const Twi<br>
<br>
void fatal(const Twine &Msg) {<br>
llvm::errs() << Msg << "\n";<br>
+ maybeCloseReproArchive();<br>
exit(1);<br>
}<br>
<br>
<br>
Modified: lld/trunk/ELF/Error.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Error.h?rev=268404&r1=268403&r2=268404&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Error.h?rev=268404&r1=268403&r2=268404&view=diff</a><br>
==============================================================================<br>
--- lld/trunk/ELF/Error.h (original)<br>
+++ lld/trunk/ELF/Error.h Tue May 3 12:30:44 2016<br>
@@ -18,6 +18,8 @@ namespace elf {<br>
extern bool HasError;<br>
extern llvm::raw_ostream *ErrorOS;<br>
<br>
+void maybeCloseReproArchive();<br>
+<br>
void log(const Twine &Msg);<br>
void warning(const Twine &Msg);<br>
<br>
<br>
Modified: lld/trunk/ELF/InputFiles.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputFiles.cpp?rev=268404&r1=268403&r2=268404&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputFiles.cpp?rev=268404&r1=268403&r2=268404&view=diff</a><br>
==============================================================================<br>
--- lld/trunk/ELF/InputFiles.cpp (original)<br>
+++ lld/trunk/ELF/InputFiles.cpp Tue May 3 12:30:44 2016<br>
@@ -372,12 +372,15 @@ MemoryBufferRef ArchiveFile::getMember(c<br>
if (!Seen.insert(C.getChildOffset()).second)<br>
return MemoryBufferRef();<br>
<br>
- if (!Config->Reproduce.empty() && C.getParent()->isThin())<br>
- copyInputFile(check(C.getFullName()));<br>
+ MemoryBufferRef Ret =<br>
+ check(C.getMemoryBufferRef(),<br>
+ "could not get the buffer for the member defining symbol " +<br>
+ Sym->getName());<br>
<br>
- return check(C.getMemoryBufferRef(),<br>
- "could not get the buffer for the member defining symbol " +<br>
- Sym->getName());<br>
+ if (C.getParent()->isThin())<br>
+ maybeCopyInputFile(check(C.getFullName()), Ret.getBuffer());<br>
+<br>
+ return Ret;<br>
}<br>
<br>
template <class ELFT><br>
<br>
Added: lld/trunk/test/ELF/reproduce-error.s<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/reproduce-error.s?rev=268404&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/reproduce-error.s?rev=268404&view=auto</a><br>
==============================================================================<br>
--- lld/trunk/test/ELF/reproduce-error.s (added)<br>
+++ lld/trunk/test/ELF/reproduce-error.s Tue May 3 12:30:44 2016<br>
@@ -0,0 +1,15 @@<br>
+# Extracting the cpio archive can get over the path limit on windows.<br>
+# REQUIRES: shell<br>
+<br>
+# RUN: rm -rf %t.dir<br>
+# RUN: mkdir -p %t.dir<br>
+# RUN: cd %t.dir<br>
+<br>
+# RUN: not ld.lld --reproduce repro abc -o t 2>&1 | FileCheck %s<br>
+# CHECK: cannot open abc: {{N|n}}o such file or directory<br>
+<br>
+# RUN: grep TRAILER repro.cpio<br>
+# RUN: cpio -id < repro.cpio<br>
+# RUN: FileCheck --check-prefix=RSP %s < repro/response.txt<br>
+# RSP: abc<br>
+# RSP: -o t<br>
<br>
Modified: lld/trunk/test/ELF/reproduce-linkerscript.s<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/reproduce-linkerscript.s?rev=268404&r1=268403&r2=268404&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/reproduce-linkerscript.s?rev=268404&r1=268403&r2=268404&view=diff</a><br>
==============================================================================<br>
--- lld/trunk/test/ELF/reproduce-linkerscript.s (original)<br>
+++ lld/trunk/test/ELF/reproduce-linkerscript.s Tue May 3 12:30:44 2016<br>
@@ -6,6 +6,7 @@<br>
# RUN: echo "INPUT(\"%t.dir/build/foo.o\")" > %t.dir/build/foo.script<br>
# RUN: cd %t.dir<br>
# RUN: ld.lld build/foo.script -o bar --reproduce repro<br>
+# RUN: cpio -id < repro.cpio<br>
# RUN: diff build/foo.script repro/%:t.dir/build/foo.script<br>
# RUN: diff build/foo.o repro/%:t.dir/build/foo.o<br>
<br>
<br>
Modified: lld/trunk/test/ELF/reproduce-thin-archive.s<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/reproduce-thin-archive.s?rev=268404&r1=268403&r2=268404&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/reproduce-thin-archive.s?rev=268404&r1=268403&r2=268404&view=diff</a><br>
==============================================================================<br>
--- lld/trunk/test/ELF/reproduce-thin-archive.s (original)<br>
+++ lld/trunk/test/ELF/reproduce-thin-archive.s Tue May 3 12:30:44 2016<br>
@@ -6,6 +6,7 @@<br>
# RUN: cd %t.dir<br>
# RUN: llvm-ar --format=gnu rcT foo.a foo.o<br>
# RUN: ld.lld -m elf_x86_64 foo.a -o bar --reproduce repro<br>
+# RUN: cpio -id < repro.cpio<br>
# RUN: diff foo.a repro/%:t.dir/foo.a<br>
# RUN: diff foo.o repro/%:t.dir/foo.o<br>
<br>
<br>
Added: lld/trunk/test/ELF/reproduce-windows.s<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/reproduce-windows.s?rev=268404&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/reproduce-windows.s?rev=268404&view=auto</a><br>
==============================================================================<br>
--- lld/trunk/test/ELF/reproduce-windows.s (added)<br>
+++ lld/trunk/test/ELF/reproduce-windows.s Tue May 3 12:30:44 2016<br>
@@ -0,0 +1,8 @@<br>
+# REQUIRES: x86<br>
+<br>
+# Test that we can create a repro archive on windows.<br>
+# RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux<br>
+# RUN: ld.lld --reproduce %t.repro %t.o -o t -shared<br>
+# RUN: cpio -t < %t.repro.cpio | FileCheck %s<br>
+# CHECK: {{^[^/\\]*}}.repro{{/|\\}}response.txt<br>
+# CHECK-NEXT: .repro{{/|\\}}{{.*}}.o<br>
<br>
Modified: lld/trunk/test/ELF/reproduce.s<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/reproduce.s?rev=268404&r1=268403&r2=268404&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/reproduce.s?rev=268404&r1=268403&r2=268404&view=diff</a><br>
==============================================================================<br>
--- lld/trunk/test/ELF/reproduce.s (original)<br>
+++ lld/trunk/test/ELF/reproduce.s Tue May 3 12:30:44 2016<br>
@@ -1,8 +1,6 @@<br>
# REQUIRES: x86<br>
<br>
-# XXX: Temporary hack to work around windows path length limitation due to<br>
-# the build dir for llvm-clang-lld-x86_64-scei-ps4-windows10pro-fast.<br>
-# When we directly generate an archive this won't be an issue.<br>
+# Extracting the cpio archive can get over the path limit on windows.<br>
# REQUIRES: shell<br>
<br>
# RUN: rm -rf %t.dir<br>
@@ -10,6 +8,7 @@<br>
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.dir/build1/foo.o<br>
# RUN: cd %t.dir<br>
# RUN: ld.lld --hash-style=gnu build1/foo.o -o bar -shared --as-needed --reproduce repro<br>
+# RUN: cpio -id < repro.cpio<br>
# RUN: diff build1/foo.o repro/%:t.dir/build1/foo.o<br>
<br>
# RUN: FileCheck %s --check-prefix=RSP < repro/response.txt<br>
@@ -24,6 +23,7 @@<br>
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.dir/build2/foo.o<br>
# RUN: cd %t.dir/build2/a/b/c<br>
# RUN: ld.lld ./../../../foo.o -o bar -shared --as-needed --reproduce repro<br>
+# RUN: cpio -id < repro.cpio<br>
# RUN: diff %t.dir/build2/foo.o repro/%:t.dir/build2/foo.o<br>
<br>
# RUN: echo "{ local: *; };" > ver<br>
@@ -33,6 +33,7 @@<br>
# RUN: ld.lld --reproduce repro2 'foo bar' -L"foo bar" -Lfile \<br>
# RUN: --dynamic-list dyn -rpath file --script file --version-script ver \<br>
# RUN: --dynamic-linker "some unusual/path"<br>
+# RUN: cpio -id < repro2.cpio<br>
# RUN: FileCheck %s --check-prefix=RSP2 < repro2/response.txt<br>
# RSP2: "{{.*}}foo bar"<br>
# RSP2-NEXT: -L "{{.*}}foo bar"<br>
@@ -43,10 +44,6 @@<br>
# RSP2-NEXT: --version-script {{.+}}ver<br>
# RSP2-NEXT: --dynamic-linker "some unusual/path"<br>
<br>
-# RUN: not ld.lld build1/foo.o -o bar -shared --as-needed --reproduce . 2>&1 \<br>
-# RUN: | FileCheck --check-prefix=ERROR %s<br>
-# ERROR: can't create directory<br>
-<br>
.globl _start<br>
_start:<br>
mov $60, %rax<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@lists.llvm.org">llvm-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits</a><br>
</blockquote></div><br></div>