Skip to content

Commit 5d5078e

Browse files
author
Owen Reynolds
committedJun 4, 2019
[llvm-ar] Reapply Fix relative thin archive path handling
Includes a fix for an introduced build failure due to a post c++11 use of std::mismatch. This fixes some thin archive relative path issues, paths are shortened where possible and paths are output correctly when using the display table command. Differential Revision: https://reviews.llvm.org/D59491 llvm-svn: 362484
1 parent 3018d50 commit 5d5078e

File tree

8 files changed

+134
-37
lines changed

8 files changed

+134
-37
lines changed
 

‎llvm/include/llvm/Object/ArchiveWriter.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ struct NewArchiveMember {
3636
bool Deterministic);
3737
};
3838

39-
std::string computeArchiveRelativePath(StringRef From, StringRef To);
39+
Expected<std::string> computeArchiveRelativePath(StringRef From, StringRef To);
4040

4141
Error writeArchive(StringRef ArcName, ArrayRef<NewArchiveMember> NewMembers,
4242
bool WriteSymtab, object::Archive::Kind Kind,

‎llvm/lib/Object/ArchiveWriter.cpp

+34-17
Original file line numberDiff line numberDiff line change
@@ -494,29 +494,46 @@ computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames,
494494
}
495495

496496
namespace llvm {
497+
498+
static ErrorOr<SmallString<128>> canonicalizePath(StringRef P) {
499+
SmallString<128> Ret = P;
500+
std::error_code Err = sys::fs::make_absolute(Ret);
501+
if (Err)
502+
return Err;
503+
sys::path::remove_dots(Ret, /*removedotdot*/ true);
504+
return Ret;
505+
}
506+
497507
// Compute the relative path from From to To.
498-
std::string computeArchiveRelativePath(StringRef From, StringRef To) {
499-
if (sys::path::is_absolute(From) || sys::path::is_absolute(To))
500-
return To;
501-
502-
StringRef DirFrom = sys::path::parent_path(From);
503-
auto FromI = sys::path::begin(DirFrom);
504-
auto ToI = sys::path::begin(To);
505-
while (*FromI == *ToI) {
506-
++FromI;
507-
++ToI;
508-
}
508+
Expected<std::string> computeArchiveRelativePath(StringRef From, StringRef To) {
509+
ErrorOr<SmallString<128>> PathToOrErr = canonicalizePath(To);
510+
ErrorOr<SmallString<128>> DirFromOrErr = canonicalizePath(From);
511+
if (!PathToOrErr || !DirFromOrErr)
512+
return errorCodeToError(std::error_code(errno, std::generic_category()));
513+
514+
const SmallString<128> &PathTo = *PathToOrErr;
515+
const SmallString<128> &DirFrom = sys::path::parent_path(*DirFromOrErr);
516+
517+
// Can't construct a relative path between different roots
518+
if (sys::path::root_name(PathTo) != sys::path::root_name(DirFrom))
519+
return sys::path::convert_to_slash(PathTo);
520+
521+
// Skip common prefixes
522+
auto FromTo =
523+
std::mismatch(sys::path::begin(DirFrom), sys::path::end(DirFrom),
524+
sys::path::begin(PathTo));
525+
auto FromI = FromTo.first;
526+
auto ToI = FromTo.second;
509527

528+
// Construct relative path
510529
SmallString<128> Relative;
511530
for (auto FromE = sys::path::end(DirFrom); FromI != FromE; ++FromI)
512-
sys::path::append(Relative, "..");
531+
sys::path::append(Relative, sys::path::Style::posix, "..");
513532

514-
for (auto ToE = sys::path::end(To); ToI != ToE; ++ToI)
515-
sys::path::append(Relative, *ToI);
533+
for (auto ToE = sys::path::end(PathTo); ToI != ToE; ++ToI)
534+
sys::path::append(Relative, sys::path::Style::posix, *ToI);
516535

517-
// Replace backslashes with slashes so that the path is portable between *nix
518-
// and Windows.
519-
return sys::path::convert_to_slash(Relative);
536+
return Relative.str();
520537
}
521538

522539
Error writeArchive(StringRef ArcName, ArrayRef<NewArchiveMember> NewMembers,

‎llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp

+8-3
Original file line numberDiff line numberDiff line change
@@ -211,9 +211,14 @@ int llvm::libDriverMain(ArrayRef<const char *> ArgsArr) {
211211
// llvm-lib uses relative paths for both regular and thin archives, unlike
212212
// standard GNU ar, which only uses relative paths for thin archives and
213213
// basenames for regular archives.
214-
for (NewArchiveMember &Member : Members)
215-
Member.MemberName =
216-
Saver.save(computeArchiveRelativePath(OutputPath, Member.MemberName));
214+
for (NewArchiveMember &Member : Members) {
215+
if (sys::path::is_relative(Member.MemberName)) {
216+
Expected<std::string> PathOrErr =
217+
computeArchiveRelativePath(OutputPath, Member.MemberName);
218+
if (PathOrErr)
219+
Member.MemberName = Saver.save(*PathOrErr);
220+
}
221+
}
217222

218223
if (Error E =
219224
writeArchive(OutputPath, Members,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
RUN: rm -rf %t && mkdir -p %t/foo/bar/
2+
RUN: mkdir -p %t/baz/
3+
RUN: yaml2obj %S/Inputs/elf.yaml -o %t/elf.o
4+
5+
RUN: cd %t && llvm-ar rTc %t/baz/internal.ar elf.o
6+
RUN: cd %t/foo && llvm-ar rTc %t/foo/bar/external.ar ../baz/internal.ar
7+
8+
RUN: FileCheck -input-file=%t/foo/bar/external.ar %s
9+
10+
CHECK: {{^}}../../elf.o/
+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
RUN: rm -rf %t && mkdir -p %t/foo/bar/
2+
3+
RUN: yaml2obj %S/Inputs/elf.yaml -o %t/foo/elf.o
4+
RUN: cp %t/foo/elf.o %t/foo/bar/elf.o
5+
RUN: cp %t/foo/bar/elf.o %t/delete.o
6+
7+
Test that modules can be added with absolute paths when the archive is created using an absolute path
8+
9+
RUN: llvm-ar rTc %t/absolute-1.ar %t/foo/elf.o %t/delete.o %t/foo/bar/elf.o
10+
RUN: llvm-ar dT %t/absolute-1.ar delete.o
11+
12+
RUN: FileCheck -input-file=%t/absolute-1.ar --check-prefixes=THIN,CHECK %s -DPATH=%/t/
13+
RUN: llvm-ar t %t/absolute-1.ar | FileCheck %s -DPATH=%/t/
14+
15+
Test that modules can be added with absolute paths when the archive is created using a relative path
16+
17+
RUN: llvm-ar rTc Output/%basename_t.tmp/absolute-2.ar %t/foo/elf.o %t/delete.o %t/foo/bar/elf.o
18+
RUN: llvm-ar dT Output/%basename_t.tmp/absolute-2.ar %t/delete.o
19+
20+
RUN: FileCheck -input-file=%t/absolute-2.ar --check-prefixes=THIN,CHECK %s -DPATH=%/t/
21+
RUN: llvm-ar t %t/absolute-2.ar | FileCheck %s -DPATH=%/t/
22+
23+
These tests must be run in %t/foo. cd %t is included on each line to make debugging this test case easier.
24+
25+
Test that modules can be added with relative paths when the archive is created using a relative path
26+
27+
RUN: cd %t/foo && llvm-ar rTc ../relative-1.ar elf.o ../delete.o bar/elf.o
28+
RUN: cd %t/foo && llvm-ar dT ../relative-1.ar delete.o
29+
30+
RUN: FileCheck -input-file=%t/relative-1.ar --check-prefixes=THIN,CHECK %s -DPATH=
31+
RUN: llvm-ar t %t/relative-1.ar | FileCheck %s -DPATH=%/t/
32+
33+
Test that modules can be added with relative paths when the archive is created using a absolute path
34+
35+
RUN: cd %t/foo && llvm-ar rTc %t/relative-2.ar elf.o ../delete.o bar/elf.o
36+
RUN: cd %t/foo && llvm-ar dT %t/relative-2.ar delete.o
37+
38+
RUN: FileCheck -input-file=%t/relative-2.ar --check-prefixes=THIN,CHECK %s -DPATH=
39+
RUN: llvm-ar t %t/relative-2.ar | FileCheck %s -DPATH=%/t/
40+
41+
THIN: !<thin>
42+
43+
CHECK-NOT: delete.o
44+
CHECK: {{^}}[[PATH]]foo/elf.o
45+
CHECK: {{^}}[[PATH]]foo/bar/elf.o

‎llvm/test/tools/llvm-objcopy/ELF/archive-unknown-members.test

+4-4
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,10 @@
2323
# RUN: llvm-ar rcT %t.thin1.a %t1.o %s
2424
# RUN: llvm-ar rcT %t.thin2.a %t2.o %s
2525

26-
# RUN: not llvm-objcopy --strip-debug %t.thin1.a 2>&1 \
27-
# RUN: | FileCheck %s --check-prefix=THIN -DARCHIVE=%t.thin1.a -DMEMBER=%s
28-
# RUN: not llvm-strip --strip-debug %t.thin2.a 2>&1 \
29-
# RUN: | FileCheck %s --check-prefix=THIN -DARCHIVE=%t.thin2.a -DMEMBER=%s
26+
# RUN: not llvm-objcopy --strip-debug %/t.thin1.a 2>&1 \
27+
# RUN: | FileCheck %s --check-prefix=THIN -DARCHIVE=%/t.thin1.a -DMEMBER=%/s
28+
# RUN: not llvm-strip --strip-debug %/t.thin2.a 2>&1 \
29+
# RUN: | FileCheck %s --check-prefix=THIN -DARCHIVE=%/t.thin2.a -DMEMBER=%/s
3030
## Verify that the first member was not modified, if a later member could not
3131
## be recognized.
3232
# RUN: cmp %t.o %t1.o

‎llvm/test/tools/llvm-readobj/thin-archive-paths.test

+3-3
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@
2323
# RUN: llvm-ar rcT c/absolute.a %t/a/b/1.o
2424

2525
# Show that absolute paths in the file header printing are correct.
26-
# RUN: llvm-readobj --file-headers c/absolute.a | FileCheck %s --check-prefix=ABS -DDIR=%t
26+
# RUN: llvm-readobj --file-headers c/absolute.a | FileCheck %s --check-prefix=ABS -DDIR=%/t
2727
# ABS: File: [[DIR]]/a/b/1.o
2828

2929
# Show that absolute paths in an error message for both archive and member are correct.
3030
# RUN: rm a/b/1.o
31-
# RUN: not llvm-readobj --file-headers %t/c/absolute.a 2>&1 | FileCheck %s --check-prefix=ERR2 -DDIR=%t
32-
# RUN: not llvm-readelf --file-headers %t/c/absolute.a 2>&1 | FileCheck %s --check-prefix=ERR2 -DDIR=%t
31+
# RUN: not llvm-readobj --file-headers %/t/c/absolute.a 2>&1 | FileCheck %s --check-prefix=ERR2 -DDIR=%/t
32+
# RUN: not llvm-readelf --file-headers %/t/c/absolute.a 2>&1 | FileCheck %s --check-prefix=ERR2 -DDIR=%/t
3333
# ERR2: error: '[[DIR]]/c/absolute.a': '[[DIR]]/a/b/1.o': {{[Nn]}}o such file or directory

‎llvm/tools/llvm-ar/llvm-ar.cpp

+29-9
Original file line numberDiff line numberDiff line change
@@ -464,9 +464,11 @@ static void doDisplayTable(StringRef Name, const object::Archive::Child &C) {
464464
}
465465

466466
if (C.getParent()->isThin()) {
467-
StringRef ParentDir = sys::path::parent_path(ArchiveName);
468-
if (!ParentDir.empty())
469-
outs() << ParentDir << '/';
467+
if (!sys::path::is_absolute(Name)) {
468+
StringRef ParentDir = sys::path::parent_path(ArchiveName);
469+
if (!ParentDir.empty())
470+
outs() << sys::path::convert_to_slash(ParentDir) << '/';
471+
}
470472
}
471473
outs() << Name << "\n";
472474
}
@@ -593,10 +595,18 @@ static void addChildMember(std::vector<NewArchiveMember> &Members,
593595
// the archive it's in, so the file resolves correctly.
594596
if (Thin && FlattenArchive) {
595597
StringSaver Saver(Alloc);
596-
Expected<std::string> FileNameOrErr = M.getFullName();
598+
Expected<std::string> FileNameOrErr = M.getName();
597599
failIfError(FileNameOrErr.takeError());
598-
NMOrErr->MemberName =
599-
Saver.save(computeArchiveRelativePath(ArchiveName, *FileNameOrErr));
600+
if (sys::path::is_absolute(*FileNameOrErr)) {
601+
NMOrErr->MemberName = Saver.save(sys::path::convert_to_slash(*FileNameOrErr));
602+
} else {
603+
FileNameOrErr = M.getFullName();
604+
failIfError(FileNameOrErr.takeError());
605+
Expected<std::string> PathOrErr =
606+
computeArchiveRelativePath(ArchiveName, *FileNameOrErr);
607+
NMOrErr->MemberName = Saver.save(
608+
PathOrErr ? *PathOrErr : sys::path::convert_to_slash(*FileNameOrErr));
609+
}
600610
}
601611
if (FlattenArchive &&
602612
identify_magic(NMOrErr->Buf->getBuffer()) == file_magic::archive) {
@@ -625,9 +635,19 @@ static void addMember(std::vector<NewArchiveMember> &Members,
625635
// For regular archives, use the basename of the object path for the member
626636
// name. For thin archives, use the full relative paths so the file resolves
627637
// correctly.
628-
NMOrErr->MemberName =
629-
Thin ? Saver.save(computeArchiveRelativePath(ArchiveName, FileName))
630-
: sys::path::filename(NMOrErr->MemberName);
638+
if (!Thin) {
639+
NMOrErr->MemberName = sys::path::filename(NMOrErr->MemberName);
640+
} else {
641+
if (sys::path::is_absolute(FileName))
642+
NMOrErr->MemberName = Saver.save(sys::path::convert_to_slash(FileName));
643+
else {
644+
Expected<std::string> PathOrErr =
645+
computeArchiveRelativePath(ArchiveName, FileName);
646+
NMOrErr->MemberName = Saver.save(
647+
PathOrErr ? *PathOrErr : sys::path::convert_to_slash(FileName));
648+
}
649+
}
650+
631651
if (FlattenArchive &&
632652
identify_magic(NMOrErr->Buf->getBuffer()) == file_magic::archive) {
633653
object::Archive &Lib = readLibrary(FileName);

0 commit comments

Comments
 (0)
Please sign in to comment.