llvm.org GIT mirror llvm / ed6564d
[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 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@362407 91177308-0d34-0410-b5e6-96231b3b80d8 Owen Reynolds 2 months ago
8 changed file(s) with 137 addition(s) and 40 deletion(s). Raw diff Collapse all Expand all
3535 bool Deterministic);
3636 };
3737
38 std::string computeArchiveRelativePath(StringRef From, StringRef To);
38 Expected computeArchiveRelativePath(StringRef From, StringRef To);
3939
4040 Error writeArchive(StringRef ArcName, ArrayRef NewMembers,
4141 bool WriteSymtab, object::Archive::Kind Kind,
493493 }
494494
495495 namespace llvm {
496
497 static ErrorOr> canonicalizePath(StringRef P) {
498 SmallString<128> Ret = P;
499 std::error_code Err = sys::fs::make_absolute(Ret);
500 if (Err)
501 return Err;
502 sys::path::remove_dots(Ret, /*removedotdot*/ true);
503 return Ret;
504 }
505
496506 // Compute the relative path from From to To.
497 std::string computeArchiveRelativePath(StringRef From, StringRef To) {
498 if (sys::path::is_absolute(From) || sys::path::is_absolute(To))
499 return To;
500
501 StringRef DirFrom = sys::path::parent_path(From);
502 auto FromI = sys::path::begin(DirFrom);
503 auto ToI = sys::path::begin(To);
504 while (*FromI == *ToI) {
505 ++FromI;
506 ++ToI;
507 }
508
507 Expected computeArchiveRelativePath(StringRef From, StringRef To) {
508 ErrorOr> PathToOrErr = canonicalizePath(To);
509 ErrorOr> DirFromOrErr = canonicalizePath(From);
510 if (!PathToOrErr || !DirFromOrErr)
511 return errorCodeToError(std::error_code(errno, std::generic_category()));
512
513 const SmallString<128> &PathTo = *PathToOrErr;
514 const SmallString<128> &DirFrom = sys::path::parent_path(*DirFromOrErr);
515
516 // Can't construct a relative path between different roots
517 if (sys::path::root_name(PathTo) != sys::path::root_name(DirFrom))
518 return sys::path::convert_to_slash(PathTo);
519
520 // Skip common prefixes
521 auto FromTo =
522 std::mismatch(sys::path::begin(DirFrom), sys::path::end(DirFrom),
523 sys::path::begin(PathTo), sys::path::end(PathTo));
524 auto FromI = FromTo.first;
525 auto ToI = FromTo.second;
526
527 // Construct relative path
509528 SmallString<128> Relative;
510529 for (auto FromE = sys::path::end(DirFrom); FromI != FromE; ++FromI)
511 sys::path::append(Relative, "..");
512
513 for (auto ToE = sys::path::end(To); ToI != ToE; ++ToI)
514 sys::path::append(Relative, *ToI);
515
516 // Replace backslashes with slashes so that the path is portable between *nix
517 // and Windows.
518 return sys::path::convert_to_slash(Relative);
530 sys::path::append(Relative, sys::path::Style::posix, "..");
531
532 for (auto ToE = sys::path::end(PathTo); ToI != ToE; ++ToI)
533 sys::path::append(Relative, sys::path::Style::posix, *ToI);
534
535 return Relative.str();
519536 }
520537
521538 Error writeArchive(StringRef ArcName, ArrayRef NewMembers,
210210 // llvm-lib uses relative paths for both regular and thin archives, unlike
211211 // standard GNU ar, which only uses relative paths for thin archives and
212212 // basenames for regular archives.
213 for (NewArchiveMember &Member : Members)
214 Member.MemberName =
215 Saver.save(computeArchiveRelativePath(OutputPath, Member.MemberName));
213 for (NewArchiveMember &Member : Members) {
214 if (sys::path::is_relative(Member.MemberName)) {
215 Expected PathOrErr =
216 computeArchiveRelativePath(OutputPath, Member.MemberName);
217 if (PathOrErr)
218 Member.MemberName = Saver.save(*PathOrErr);
219 }
220 }
216221
217222 if (Error E =
218223 writeArchive(OutputPath, Members,
0 RUN: rm -rf %t && mkdir -p %t/foo/bar/
1 RUN: mkdir -p %t/baz/
2 RUN: yaml2obj %S/Inputs/elf.yaml -o %t/elf.o
3
4 RUN: cd %t && llvm-ar rTc %t/baz/internal.ar elf.o
5 RUN: cd %t/foo && llvm-ar rTc %t/foo/bar/external.ar ../baz/internal.ar
6
7 RUN: FileCheck -input-file=%t/foo/bar/external.ar %s
8
9 CHECK: {{^}}../../elf.o/
0 RUN: rm -rf %t && mkdir -p %t/foo/bar/
1
2 RUN: yaml2obj %S/Inputs/elf.yaml -o %t/foo/elf.o
3 RUN: cp %t/foo/elf.o %t/foo/bar/elf.o
4 RUN: cp %t/foo/bar/elf.o %t/delete.o
5
6 Test that modules can be added with absolute paths when the archive is created using an absolute path
7
8 RUN: llvm-ar rTc %t/absolute-1.ar %t/foo/elf.o %t/delete.o %t/foo/bar/elf.o
9 RUN: llvm-ar dT %t/absolute-1.ar delete.o
10
11 RUN: FileCheck -input-file=%t/absolute-1.ar --check-prefixes=THIN,CHECK %s -DPATH=%/t/
12 RUN: llvm-ar t %t/absolute-1.ar | FileCheck %s -DPATH=%/t/
13
14 Test that modules can be added with absolute paths when the archive is created using a relative path
15
16 RUN: llvm-ar rTc Output/%basename_t.tmp/absolute-2.ar %t/foo/elf.o %t/delete.o %t/foo/bar/elf.o
17 RUN: llvm-ar dT Output/%basename_t.tmp/absolute-2.ar %t/delete.o
18
19 RUN: FileCheck -input-file=%t/absolute-2.ar --check-prefixes=THIN,CHECK %s -DPATH=%/t/
20 RUN: llvm-ar t %t/absolute-2.ar | FileCheck %s -DPATH=%/t/
21
22 These tests must be run in %t/foo. cd %t is included on each line to make debugging this test case easier.
23
24 Test that modules can be added with relative paths when the archive is created using a relative path
25
26 RUN: cd %t/foo && llvm-ar rTc ../relative-1.ar elf.o ../delete.o bar/elf.o
27 RUN: cd %t/foo && llvm-ar dT ../relative-1.ar delete.o
28
29 RUN: FileCheck -input-file=%t/relative-1.ar --check-prefixes=THIN,CHECK %s -DPATH=
30 RUN: llvm-ar t %t/relative-1.ar | FileCheck %s -DPATH=%/t/
31
32 Test that modules can be added with relative paths when the archive is created using a absolute path
33
34 RUN: cd %t/foo && llvm-ar rTc %t/relative-2.ar elf.o ../delete.o bar/elf.o
35 RUN: cd %t/foo && llvm-ar dT %t/relative-2.ar delete.o
36
37 RUN: FileCheck -input-file=%t/relative-2.ar --check-prefixes=THIN,CHECK %s -DPATH=
38 RUN: llvm-ar t %t/relative-2.ar | FileCheck %s -DPATH=%/t/
39
40 THIN: !
41
42 CHECK-NOT: delete.o
43 CHECK: {{^}}[[PATH]]foo/elf.o
44 CHECK: {{^}}[[PATH]]foo/bar/elf.o
2222 # RUN: llvm-ar rcT %t.thin1.a %t1.o %s
2323 # RUN: llvm-ar rcT %t.thin2.a %t2.o %s
2424
25 # RUN: not llvm-objcopy --strip-debug %t.thin1.a 2>&1 \
26 # RUN: | FileCheck %s --check-prefix=THIN -DARCHIVE=%t.thin1.a -DMEMBER=%s
27 # RUN: not llvm-strip --strip-debug %t.thin2.a 2>&1 \
28 # RUN: | FileCheck %s --check-prefix=THIN -DARCHIVE=%t.thin2.a -DMEMBER=%s
25 # RUN: not llvm-objcopy --strip-debug %/t.thin1.a 2>&1 \
26 # RUN: | FileCheck %s --check-prefix=THIN -DARCHIVE=%/t.thin1.a -DMEMBER=%/s
27 # RUN: not llvm-strip --strip-debug %/t.thin2.a 2>&1 \
28 # RUN: | FileCheck %s --check-prefix=THIN -DARCHIVE=%/t.thin2.a -DMEMBER=%/s
2929 ## Verify that the first member was not modified, if a later member could not
3030 ## be recognized.
3131 # RUN: cmp %t.o %t1.o
2222 # RUN: llvm-ar rcT c/absolute.a %t/a/b/1.o
2323
2424 # Show that absolute paths in the file header printing are correct.
25 # RUN: llvm-readobj --file-headers c/absolute.a | FileCheck %s --check-prefix=ABS -DDIR=%t
25 # RUN: llvm-readobj --file-headers c/absolute.a | FileCheck %s --check-prefix=ABS -DDIR=%/t
2626 # ABS: File: [[DIR]]/a/b/1.o
2727
2828 # Show that absolute paths in an error message for both archive and member are correct.
2929 # RUN: rm a/b/1.o
30 # RUN: not llvm-readobj --file-headers %t/c/absolute.a 2>&1 | FileCheck %s --check-prefix=ERR2 -DDIR=%t
31 # RUN: not llvm-readelf --file-headers %t/c/absolute.a 2>&1 | FileCheck %s --check-prefix=ERR2 -DDIR=%t
30 # RUN: not llvm-readobj --file-headers %/t/c/absolute.a 2>&1 | FileCheck %s --check-prefix=ERR2 -DDIR=%/t
31 # RUN: not llvm-readelf --file-headers %/t/c/absolute.a 2>&1 | FileCheck %s --check-prefix=ERR2 -DDIR=%/t
3232 # ERR2: error: '[[DIR]]/c/absolute.a': '[[DIR]]/a/b/1.o': {{[Nn]}}o such file or directory
463463 }
464464
465465 if (C.getParent()->isThin()) {
466 StringRef ParentDir = sys::path::parent_path(ArchiveName);
467 if (!ParentDir.empty())
468 outs() << ParentDir << '/';
466 if (!sys::path::is_absolute(Name)) {
467 StringRef ParentDir = sys::path::parent_path(ArchiveName);
468 if (!ParentDir.empty())
469 outs() << sys::path::convert_to_slash(ParentDir) << '/';
470 }
469471 }
470472 outs() << Name << "\n";
471473 }
592594 // the archive it's in, so the file resolves correctly.
593595 if (Thin && FlattenArchive) {
594596 StringSaver Saver(Alloc);
595 Expected FileNameOrErr = M.getFullName();
597 Expected FileNameOrErr = M.getName();
596598 failIfError(FileNameOrErr.takeError());
597 NMOrErr->MemberName =
598 Saver.save(computeArchiveRelativePath(ArchiveName, *FileNameOrErr));
599 if (sys::path::is_absolute(*FileNameOrErr)) {
600 NMOrErr->MemberName = Saver.save(sys::path::convert_to_slash(*FileNameOrErr));
601 } else {
602 FileNameOrErr = M.getFullName();
603 failIfError(FileNameOrErr.takeError());
604 Expected PathOrErr =
605 computeArchiveRelativePath(ArchiveName, *FileNameOrErr);
606 NMOrErr->MemberName = Saver.save(
607 PathOrErr ? *PathOrErr : sys::path::convert_to_slash(*FileNameOrErr));
608 }
599609 }
600610 if (FlattenArchive &&
601611 identify_magic(NMOrErr->Buf->getBuffer()) == file_magic::archive) {
624634 // For regular archives, use the basename of the object path for the member
625635 // name. For thin archives, use the full relative paths so the file resolves
626636 // correctly.
627 NMOrErr->MemberName =
628 Thin ? Saver.save(computeArchiveRelativePath(ArchiveName, FileName))
629 : sys::path::filename(NMOrErr->MemberName);
637 if (!Thin) {
638 NMOrErr->MemberName = sys::path::filename(NMOrErr->MemberName);
639 } else {
640 if (sys::path::is_absolute(FileName))
641 NMOrErr->MemberName = Saver.save(sys::path::convert_to_slash(FileName));
642 else {
643 Expected PathOrErr =
644 computeArchiveRelativePath(ArchiveName, FileName);
645 NMOrErr->MemberName = Saver.save(
646 PathOrErr ? *PathOrErr : sys::path::convert_to_slash(FileName));
647 }
648 }
649
630650 if (FlattenArchive &&
631651 identify_magic(NMOrErr->Buf->getBuffer()) == file_magic::archive) {
632652 object::Archive &Lib = readLibrary(FileName);