[llvm] r353995 - [llvm-ar][libObject] Fix relative paths when nesting thin archives.

Jordan Rupprecht via llvm-commits llvm-commits at lists.llvm.org
Thu Feb 14 10:59:55 PST 2019


That code was a straight move (just to move it outside the static methods),
so I didn't look at it. I can see if convert_to_slash works.

On Thu, Feb 14, 2019 at 10:57 AM Saleem Abdulrasool <compnerd at compnerd.org>
wrote:

> Is it not possible to use `sys::path::convert_to_slash` instead of the
> `#ifdef _WIN32`?  I think at the very least that should be `LLVM_ON_WIN32`
> (due to Cygwin's behaviours).
>
> On Wed, Feb 13, 2019 at 3:39 PM Jordan Rupprecht via llvm-commits <
> llvm-commits at lists.llvm.org> wrote:
>
>> Author: rupprecht
>> Date: Wed Feb 13 15:39:41 2019
>> New Revision: 353995
>>
>> URL: http://llvm.org/viewvc/llvm-project?rev=353995&view=rev
>> Log:
>> [llvm-ar][libObject] Fix relative paths when nesting thin archives.
>>
>> Summary:
>> When adding one thin archive to another, we currently chop off the
>> relative path to the flattened members. For instance, when adding
>> `foo/child.a` (which contains `x.txt`) to `parent.a`, when flattening it we
>> should add it as `foo/x.txt` (which exists) instead of `x.txt` (which does
>> not exist).
>>
>> As a note, this also undoes the `IsNew` parameter of handling relative
>> paths in r288280. The unit test there still passes.
>>
>> This was reported as part of testing the kernel build with llvm-ar:
>> https://patchwork.kernel.org/patch/10767545/ (see the second point).
>>
>> Reviewers: mstorsjo, pcc, ruiu, davide, david2050, inglorion
>>
>> Reviewed By: ruiu
>>
>> Subscribers: void, jdoerfert, tpimh, mgorny, hans, nickdesaulniers,
>> hiraditya, llvm-commits
>>
>> Tags: #llvm
>>
>> Differential Revision: https://reviews.llvm.org/D57842
>>
>> Added:
>>     llvm/trunk/test/tools/llvm-ar/flatten-thin-archive-directories.test
>>     llvm/trunk/test/tools/llvm-lib/thin-relative.test
>> Modified:
>>     llvm/trunk/include/llvm/Object/ArchiveWriter.h
>>     llvm/trunk/lib/Object/ArchiveWriter.cpp
>>     llvm/trunk/lib/ToolDrivers/llvm-lib/CMakeLists.txt
>>     llvm/trunk/lib/ToolDrivers/llvm-lib/LibDriver.cpp
>>     llvm/trunk/test/tools/llvm-ar/flatten-thin-archive.test
>>     llvm/trunk/tools/llvm-ar/llvm-ar.cpp
>>
>> Modified: llvm/trunk/include/llvm/Object/ArchiveWriter.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Object/ArchiveWriter.h?rev=353995&r1=353994&r2=353995&view=diff
>>
>> ==============================================================================
>> --- llvm/trunk/include/llvm/Object/ArchiveWriter.h (original)
>> +++ llvm/trunk/include/llvm/Object/ArchiveWriter.h Wed Feb 13 15:39:41
>> 2019
>> @@ -26,7 +26,6 @@ struct NewArchiveMember {
>>    sys::TimePoint<std::chrono::seconds> ModTime;
>>    unsigned UID = 0, GID = 0, Perms = 0644;
>>
>> -  bool IsNew = false;
>>    NewArchiveMember() = default;
>>    NewArchiveMember(MemoryBufferRef BufRef);
>>
>> @@ -37,6 +36,8 @@ struct NewArchiveMember {
>>                                              bool Deterministic);
>>  };
>>
>> +std::string computeArchiveRelativePath(StringRef From, StringRef To);
>> +
>>  Error writeArchive(StringRef ArcName, ArrayRef<NewArchiveMember>
>> NewMembers,
>>                     bool WriteSymtab, object::Archive::Kind Kind,
>>                     bool Deterministic, bool Thin,
>>
>> Modified: llvm/trunk/lib/Object/ArchiveWriter.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Object/ArchiveWriter.cpp?rev=353995&r1=353994&r2=353995&view=diff
>>
>> ==============================================================================
>> --- llvm/trunk/lib/Object/ArchiveWriter.cpp (original)
>> +++ llvm/trunk/lib/Object/ArchiveWriter.cpp Wed Feb 13 15:39:41 2019
>> @@ -48,7 +48,6 @@ NewArchiveMember::getOldMember(const obj
>>      return BufOrErr.takeError();
>>
>>    NewArchiveMember M;
>> -  assert(M.IsNew == false);
>>    M.Buf = MemoryBuffer::getMemBuffer(*BufOrErr, false);
>>    M.MemberName = M.Buf->getBufferIdentifier();
>>    if (!Deterministic) {
>> @@ -98,7 +97,6 @@ Expected<NewArchiveMember> NewArchiveMem
>>      return errorCodeToError(std::error_code(errno,
>> std::generic_category()));
>>
>>    NewArchiveMember M;
>> -  M.IsNew = true;
>>    M.Buf = std::move(*MemberBufferOrErr);
>>    M.MemberName = M.Buf->getBufferIdentifier();
>>    if (!Deterministic) {
>> @@ -191,35 +189,6 @@ static bool useStringTable(bool Thin, St
>>    return Thin || Name.size() >= 16 || Name.contains('/');
>>  }
>>
>> -// Compute the relative path from From to To.
>> -static std::string computeRelativePath(StringRef From, StringRef To) {
>> -  if (sys::path::is_absolute(From) || sys::path::is_absolute(To))
>> -    return To;
>> -
>> -  StringRef DirFrom = sys::path::parent_path(From);
>> -  auto FromI = sys::path::begin(DirFrom);
>> -  auto ToI = sys::path::begin(To);
>> -  while (*FromI == *ToI) {
>> -    ++FromI;
>> -    ++ToI;
>> -  }
>> -
>> -  SmallString<128> Relative;
>> -  for (auto FromE = sys::path::end(DirFrom); FromI != FromE; ++FromI)
>> -    sys::path::append(Relative, "..");
>> -
>> -  for (auto ToE = sys::path::end(To); ToI != ToE; ++ToI)
>> -    sys::path::append(Relative, *ToI);
>> -
>> -#ifdef _WIN32
>> -  // Replace backslashes with slashes so that the path is portable
>> between *nix
>> -  // and Windows.
>> -  std::replace(Relative.begin(), Relative.end(), '\\', '/');
>> -#endif
>> -
>> -  return Relative.str();
>> -}
>> -
>>  static bool is64BitKind(object::Archive::Kind Kind) {
>>    switch (Kind) {
>>    case object::Archive::K_GNU:
>> @@ -234,27 +203,11 @@ static bool is64BitKind(object::Archive:
>>    llvm_unreachable("not supported for writting");
>>  }
>>
>> -static void addToStringTable(raw_ostream &Out, StringRef ArcName,
>> -                             const NewArchiveMember &M, bool Thin) {
>> -  StringRef ID = M.Buf->getBufferIdentifier();
>> -  if (Thin) {
>> -    if (M.IsNew)
>> -      Out << computeRelativePath(ArcName, ID);
>> -    else
>> -      Out << ID;
>> -  } else
>> -    Out << M.MemberName;
>> -  Out << "/\n";
>> -}
>> -
>> -static void printMemberHeader(raw_ostream &Out, uint64_t Pos,
>> -                              raw_ostream &StringTable,
>> -                              StringMap<uint64_t> &MemberNames,
>> -                              object::Archive::Kind Kind, bool Thin,
>> -                              StringRef ArcName, const NewArchiveMember
>> &M,
>> -                              sys::TimePoint<std::chrono::seconds>
>> ModTime,
>> -                              unsigned Size) {
>> -
>> +static void
>> +printMemberHeader(raw_ostream &Out, uint64_t Pos, raw_ostream
>> &StringTable,
>> +                  StringMap<uint64_t> &MemberNames,
>> object::Archive::Kind Kind,
>> +                  bool Thin, const NewArchiveMember &M,
>> +                  sys::TimePoint<std::chrono::seconds> ModTime, unsigned
>> Size) {
>>    if (isBSDLike(Kind))
>>      return printBSDMemberHeader(Out, Pos, M.MemberName, ModTime, M.UID,
>> M.GID,
>>                                  M.Perms, Size);
>> @@ -265,12 +218,12 @@ static void printMemberHeader(raw_ostrea
>>    uint64_t NamePos;
>>    if (Thin) {
>>      NamePos = StringTable.tell();
>> -    addToStringTable(StringTable, ArcName, M, Thin);
>> +    StringTable << M.MemberName << "/\n";
>>    } else {
>>      auto Insertion = MemberNames.insert({M.MemberName, uint64_t(0)});
>>      if (Insertion.second) {
>>        Insertion.first->second = StringTable.tell();
>> -      addToStringTable(StringTable, ArcName, M, Thin);
>> +      StringTable << M.MemberName << "/\n";
>>      }
>>      NamePos = Insertion.first->second;
>>    }
>> @@ -432,8 +385,8 @@ getSymbols(MemoryBufferRef Buf, raw_ostr
>>
>>  static Expected<std::vector<MemberData>>
>>  computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames,
>> -                  object::Archive::Kind Kind, bool Thin, StringRef
>> ArcName,
>> -                  bool Deterministic, ArrayRef<NewArchiveMember>
>> NewMembers) {
>> +                  object::Archive::Kind Kind, bool Thin, bool
>> Deterministic,
>> +                  ArrayRef<NewArchiveMember> NewMembers) {
>>    static char PaddingData[8] = {'\n', '\n', '\n', '\n', '\n', '\n',
>> '\n', '\n'};
>>
>>    // This ignores the symbol table, but we only need the value mod 8 and
>> the
>> @@ -520,8 +473,8 @@ computeMemberData(raw_ostream &StringTab
>>        ModTime = sys::toTimePoint(FilenameCount[M.MemberName]++);
>>      else
>>        ModTime = M.ModTime;
>> -    printMemberHeader(Out, Pos, StringTable, MemberNames, Kind, Thin,
>> ArcName,
>> -                      M, ModTime, Buf.getBufferSize() + MemberPadding);
>> +    printMemberHeader(Out, Pos, StringTable, MemberNames, Kind, Thin, M,
>> +                      ModTime, Buf.getBufferSize() + MemberPadding);
>>      Out.flush();
>>
>>      Expected<std::vector<unsigned>> Symbols =
>> @@ -540,11 +493,40 @@ computeMemberData(raw_ostream &StringTab
>>    return Ret;
>>  }
>>
>> -Error llvm::writeArchive(StringRef ArcName,
>> -                         ArrayRef<NewArchiveMember> NewMembers,
>> -                         bool WriteSymtab, object::Archive::Kind Kind,
>> -                         bool Deterministic, bool Thin,
>> -                         std::unique_ptr<MemoryBuffer> OldArchiveBuf) {
>> +namespace llvm {
>> +// Compute the relative path from From to To.
>> +std::string computeArchiveRelativePath(StringRef From, StringRef To) {
>> +  if (sys::path::is_absolute(From) || sys::path::is_absolute(To))
>> +    return To;
>> +
>> +  StringRef DirFrom = sys::path::parent_path(From);
>> +  auto FromI = sys::path::begin(DirFrom);
>> +  auto ToI = sys::path::begin(To);
>> +  while (*FromI == *ToI) {
>> +    ++FromI;
>> +    ++ToI;
>> +  }
>> +
>> +  SmallString<128> Relative;
>> +  for (auto FromE = sys::path::end(DirFrom); FromI != FromE; ++FromI)
>> +    sys::path::append(Relative, "..");
>> +
>> +  for (auto ToE = sys::path::end(To); ToI != ToE; ++ToI)
>> +    sys::path::append(Relative, *ToI);
>> +
>> +#ifdef _WIN32
>> +  // Replace backslashes with slashes so that the path is portable
>> between *nix
>> +  // and Windows.
>> +  std::replace(Relative.begin(), Relative.end(), '\\', '/');
>> +#endif
>> +
>> +  return Relative.str();
>> +}
>> +
>> +Error writeArchive(StringRef ArcName, ArrayRef<NewArchiveMember>
>> NewMembers,
>> +                   bool WriteSymtab, object::Archive::Kind Kind,
>> +                   bool Deterministic, bool Thin,
>> +                   std::unique_ptr<MemoryBuffer> OldArchiveBuf) {
>>    assert((!Thin || !isBSDLike(Kind)) && "Only the gnu format has a thin
>> mode");
>>
>>    SmallString<0> SymNamesBuf;
>> @@ -553,7 +535,7 @@ Error llvm::writeArchive(StringRef ArcNa
>>    raw_svector_ostream StringTable(StringTableBuf);
>>
>>    Expected<std::vector<MemberData>> DataOrErr = computeMemberData(
>> -      StringTable, SymNames, Kind, Thin, ArcName, Deterministic,
>> NewMembers);
>> +      StringTable, SymNames, Kind, Thin, Deterministic, NewMembers);
>>    if (Error E = DataOrErr.takeError())
>>      return E;
>>    std::vector<MemberData> &Data = *DataOrErr;
>> @@ -630,3 +612,5 @@ Error llvm::writeArchive(StringRef ArcNa
>>
>>    return Temp->keep(ArcName);
>>  }
>> +
>> +} // namespace llvm
>>
>> Modified: llvm/trunk/lib/ToolDrivers/llvm-lib/CMakeLists.txt
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ToolDrivers/llvm-lib/CMakeLists.txt?rev=353995&r1=353994&r2=353995&view=diff
>>
>> ==============================================================================
>> --- llvm/trunk/lib/ToolDrivers/llvm-lib/CMakeLists.txt (original)
>> +++ llvm/trunk/lib/ToolDrivers/llvm-lib/CMakeLists.txt Wed Feb 13
>> 15:39:41 2019
>> @@ -1,3 +1,10 @@
>> +set(LLVM_LINK_COMPONENTS
>> +  BinaryFormat
>> +  Object
>> +  Option
>> +  Support
>> +  )
>> +
>>  set(LLVM_TARGET_DEFINITIONS Options.td)
>>  tablegen(LLVM Options.inc -gen-opt-parser-defs)
>>  add_public_tablegen_target(LibOptionsTableGen)
>>
>> Modified: llvm/trunk/lib/ToolDrivers/llvm-lib/LibDriver.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ToolDrivers/llvm-lib/LibDriver.cpp?rev=353995&r1=353994&r2=353995&view=diff
>>
>> ==============================================================================
>> --- llvm/trunk/lib/ToolDrivers/llvm-lib/LibDriver.cpp (original)
>> +++ llvm/trunk/lib/ToolDrivers/llvm-lib/LibDriver.cpp Wed Feb 13 15:39:41
>> 2019
>> @@ -208,6 +208,13 @@ int llvm::libDriverMain(ArrayRef<const c
>>
>>    // Create an archive file.
>>    std::string OutputPath = getOutputPath(&Args, Members[0]);
>> +  // llvm-lib uses relative paths for both regular and thin archives,
>> unlike
>> +  // standard GNU ar, which only uses relative paths for thin archives
>> and
>> +  // basenames for regular archives.
>> +  for (NewArchiveMember &Member : Members)
>> +    Member.MemberName =
>> +        Saver.save(computeArchiveRelativePath(OutputPath,
>> Member.MemberName));
>> +
>>    if (Error E =
>>            writeArchive(OutputPath, Members,
>>                         /*WriteSymtab=*/true, object::Archive::K_GNU,
>>
>> Added: llvm/trunk/test/tools/llvm-ar/flatten-thin-archive-directories.test
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-ar/flatten-thin-archive-directories.test?rev=353995&view=auto
>>
>> ==============================================================================
>> --- llvm/trunk/test/tools/llvm-ar/flatten-thin-archive-directories.test
>> (added)
>> +++ llvm/trunk/test/tools/llvm-ar/flatten-thin-archive-directories.test
>> Wed Feb 13 15:39:41 2019
>> @@ -0,0 +1,15 @@
>> +# This test creates a thin archive in a directory and adds it to a thin
>> archive
>> +# in the parent directory. The relative path should be included when
>> flattening
>> +# the archive.
>> +
>> +RUN: mkdir -p %t/foo
>> +RUN: touch %t/foo/a.txt
>> +RUN: rm -f %t/archive.a %t/foo/archive.a
>> +
>> +# These tests must be run in the same directory as %t/archive.a. cd %t is
>> +# included on each line to make debugging this test case easier.
>> +RUN: cd %t && llvm-ar rcST foo/archive.a foo/a.txt
>> +RUN: cd %t && llvm-ar rcST archive.a foo/archive.a
>> +RUN: cd %t && llvm-ar t archive.a | FileCheck %s --match-full-lines
>> +
>> +CHECK: foo/a.txt
>>
>> Modified: llvm/trunk/test/tools/llvm-ar/flatten-thin-archive.test
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-ar/flatten-thin-archive.test?rev=353995&r1=353994&r2=353995&view=diff
>>
>> ==============================================================================
>> --- llvm/trunk/test/tools/llvm-ar/flatten-thin-archive.test (original)
>> +++ llvm/trunk/test/tools/llvm-ar/flatten-thin-archive.test Wed Feb 13
>> 15:39:41 2019
>> @@ -6,7 +6,7 @@
>>  # flattened members appearing together.
>>
>>  RUN: touch %t-a.txt %t-b.txt %t-c.txt %t-d.txt %t-e.txt
>> -RUN: rm -f %t-a-plus-b.a %t.a
>> +RUN: rm -f %t-a-plus-b.a %t-d-plus-e.a %t.a
>>  RUN: llvm-ar rcsT %t-a-plus-b.a %t-a.txt %t-b.txt
>>  RUN: llvm-ar rcs %t-d-plus-e.a %t-d.txt %t-e.txt
>>  RUN: llvm-ar rcsT %t.a %t-a-plus-b.a %t-c.txt %t-d-plus-e.a
>>
>> Added: llvm/trunk/test/tools/llvm-lib/thin-relative.test
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-lib/thin-relative.test?rev=353995&view=auto
>>
>> ==============================================================================
>> --- llvm/trunk/test/tools/llvm-lib/thin-relative.test (added)
>> +++ llvm/trunk/test/tools/llvm-lib/thin-relative.test Wed Feb 13 15:39:41
>> 2019
>> @@ -0,0 +1,13 @@
>> +RUN: rm -rf %t
>> +RUN: mkdir -p %t/foo
>> +RUN: cd %t
>> +
>> +RUN: llvm-mc -triple=x86_64-pc-windows-msvc -filetype=obj -o foo/obj.o
>> %S/Inputs/a.s
>> +
>> +RUN: llvm-lib -out:archive.a -llvmlibthin foo/obj.o
>> +RUN: llvm-ar t archive.a | FileCheck %s --check-prefix=PARENT-DIR
>> --match-full-lines
>> +PARENT-DIR: foo/obj.o
>> +
>> +RUN: llvm-lib -out:foo/archive.a -llvmlibthin foo/obj.o
>> +RUN: llvm-ar t foo/archive.a | FileCheck %s --check-prefix=SAME-DIR
>> --match-full-lines
>> +SAME-DIR: foo/obj.o
>>
>> Modified: llvm/trunk/tools/llvm-ar/llvm-ar.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-ar/llvm-ar.cpp?rev=353995&r1=353994&r2=353995&view=diff
>>
>> ==============================================================================
>> --- llvm/trunk/tools/llvm-ar/llvm-ar.cpp (original)
>> +++ llvm/trunk/tools/llvm-ar/llvm-ar.cpp Wed Feb 13 15:39:41 2019
>> @@ -193,6 +193,9 @@ static std::string ArchiveName;
>>  // on the command line.
>>  static std::vector<StringRef> Members;
>>
>> +// Static buffer to hold StringRefs.
>> +static BumpPtrAllocator Alloc;
>> +
>>  // Extract the member filename from the command line for the [relpos]
>> argument
>>  // associated with a, b, and i modifiers
>>  static void getRelPos() {
>> @@ -545,6 +548,15 @@ static void addChildMember(std::vector<N
>>    Expected<NewArchiveMember> NMOrErr =
>>        NewArchiveMember::getOldMember(M, Deterministic);
>>    failIfError(NMOrErr.takeError());
>> +  // If the child member we're trying to add is thin, use the path
>> relative to
>> +  // the archive it's in, so the file resolves correctly.
>> +  if (Thin && FlattenArchive) {
>> +    StringSaver Saver(Alloc);
>> +    Expected<std::string> FileNameOrErr = M.getFullName();
>> +    failIfError(FileNameOrErr.takeError());
>> +    NMOrErr->MemberName =
>> +        Saver.save(computeArchiveRelativePath(ArchiveName,
>> *FileNameOrErr));
>> +  }
>>    if (FlattenArchive &&
>>        identify_magic(NMOrErr->Buf->getBuffer()) == file_magic::archive) {
>>      Expected<std::string> FileNameOrErr = M.getFullName();
>> @@ -568,6 +580,13 @@ static void addMember(std::vector<NewArc
>>    Expected<NewArchiveMember> NMOrErr =
>>        NewArchiveMember::getFile(FileName, Deterministic);
>>    failIfError(NMOrErr.takeError(), FileName);
>> +  StringSaver Saver(Alloc);
>> +  // For regular archives, use the basename of the object path for the
>> member
>> +  // name. For thin archives, use the full relative paths so the file
>> resolves
>> +  // correctly.
>> +  NMOrErr->MemberName =
>> +      Thin ? Saver.save(computeArchiveRelativePath(ArchiveName,
>> FileName))
>> +           : sys::path::filename(NMOrErr->MemberName);
>>    if (FlattenArchive &&
>>        identify_magic(NMOrErr->Buf->getBuffer()) == file_magic::archive) {
>>      object::Archive &Lib = readLibrary(FileName);
>> @@ -581,8 +600,6 @@ static void addMember(std::vector<NewArc
>>        return;
>>      }
>>    }
>> -  // Use the basename of the object path for the member name.
>> -  NMOrErr->MemberName = sys::path::filename(NMOrErr->MemberName);
>>    Members.push_back(std::move(*NMOrErr));
>>  }
>>
>> @@ -672,7 +689,7 @@ computeNewArchiveMembers(ArchiveOperatio
>>            computeInsertAction(Operation, Child, Name, MemberI);
>>        switch (Action) {
>>        case IA_AddOldMember:
>> -        addChildMember(Ret, Child);
>> +        addChildMember(Ret, Child, /*FlattenArchive=*/Thin);
>>          break;
>>        case IA_AddNewMember:
>>          addMember(Ret, *MemberI);
>> @@ -680,7 +697,7 @@ computeNewArchiveMembers(ArchiveOperatio
>>        case IA_Delete:
>>          break;
>>        case IA_MoveOldMember:
>> -        addChildMember(Moved, Child);
>> +        addChildMember(Moved, Child, /*FlattenArchive=*/Thin);
>>          break;
>>        case IA_MoveNewMember:
>>          addMember(Moved, *MemberI);
>> @@ -899,7 +916,7 @@ static void runMRIScript() {
>>        {
>>          Error Err = Error::success();
>>          for (auto &Member : Lib.children(Err))
>> -          addChildMember(NewMembers, Member);
>> +          addChildMember(NewMembers, Member, /*FlattenArchive=*/Thin);
>>          failIfError(std::move(Err));
>>        }
>>        break;
>> @@ -951,7 +968,6 @@ static bool handleGenericOption(StringRe
>>
>>  static int ar_main(int argc, char **argv) {
>>    SmallVector<const char *, 0> Argv(argv, argv + argc);
>> -  BumpPtrAllocator Alloc;
>>    StringSaver Saver(Alloc);
>>    cl::ExpandResponseFiles(Saver, cl::TokenizeGNUCommandLine, Argv);
>>    for (size_t i = 1; i < Argv.size(); ++i) {
>>
>>
>> _______________________________________________
>> llvm-commits mailing list
>> llvm-commits at lists.llvm.org
>> https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>>
>
>
> --
> Saleem Abdulrasool
> compnerd (at) compnerd (dot) org
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20190214/c095cf89/attachment-0001.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/pkcs7-signature
Size: 4849 bytes
Desc: S/MIME Cryptographic Signature
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20190214/c095cf89/attachment-0001.bin>


More information about the llvm-commits mailing list