Skip to content

Commit fade9cb

Browse files
author
Owen Reynolds
committed
[llvm-ar] Fix relative thin archive path handling
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: 362407
1 parent dab879d commit fade9cb

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), sys::path::end(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)