[llvm] 10f2233 - [llvm-libtool-darwin] Add support for -dependency_info

Keith Smiley via llvm-commits llvm-commits at lists.llvm.org
Mon Oct 3 09:54:18 PDT 2022


Author: Keith Smiley
Date: 2022-10-03T09:53:02-07:00
New Revision: 10f22335f3b7c7b78b54ee6b995f6ed97e4c225d

URL: https://github.com/llvm/llvm-project/commit/10f22335f3b7c7b78b54ee6b995f6ed97e4c225d
DIFF: https://github.com/llvm/llvm-project/commit/10f22335f3b7c7b78b54ee6b995f6ed97e4c225d.diff

LOG: [llvm-libtool-darwin] Add support for -dependency_info

When using llvm-libtool-darwin as a drop in replacement for cctools
libtool, Xcode expects you to create a dependency info file. This file
is a very simple format describing the input files, the output files,
and the version of the tool. This logic is mirrored from that of
ld64.lld, which supports creating this file as well. Ideally we could
extract it, but I don't think we want to throw this into one of the
grab-bag libraries given how small the logic is.

Differential Revision: https://reviews.llvm.org/D134322

Added: 
    llvm/test/tools/llvm-libtool-darwin/Inputs/DependencyDump.py
    llvm/test/tools/llvm-libtool-darwin/dependency-info.test
    llvm/tools/llvm-libtool-darwin/DependencyInfo.h

Modified: 
    llvm/tools/llvm-libtool-darwin/llvm-libtool-darwin.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/test/tools/llvm-libtool-darwin/Inputs/DependencyDump.py b/llvm/test/tools/llvm-libtool-darwin/Inputs/DependencyDump.py
new file mode 100755
index 0000000000000..ddf9873614785
--- /dev/null
+++ b/llvm/test/tools/llvm-libtool-darwin/Inputs/DependencyDump.py
@@ -0,0 +1,26 @@
+#
+# Dump the dependency file (produced with -dependency_info) to text
+# format for testing purposes.
+#
+
+import sys
+
+f = open(sys.argv[1], "rb")
+byte = f.read(1)
+while byte != b'':
+    if byte == b'\x00':
+        sys.stdout.write("version: ")
+    elif byte == b'\x10':
+        sys.stdout.write("input-file: ")
+    elif byte == b'\x11':
+        sys.stdout.write("not-found: ")
+    elif byte == b'\x40':
+        sys.stdout.write("output-file: ")
+    byte = f.read(1)
+    while byte != b'\x00':
+        sys.stdout.write(byte.decode("ascii"))
+        byte = f.read(1)
+    sys.stdout.write("\n")
+    byte = f.read(1)
+
+f.close()

diff  --git a/llvm/test/tools/llvm-libtool-darwin/dependency-info.test b/llvm/test/tools/llvm-libtool-darwin/dependency-info.test
new file mode 100644
index 0000000000000..72e63d5279b39
--- /dev/null
+++ b/llvm/test/tools/llvm-libtool-darwin/dependency-info.test
@@ -0,0 +1,19 @@
+## This test validates the format of the dependency info file
+# RUN: rm -rf %t; mkdir -p %t
+
+# RUN: yaml2obj %S/Inputs/input1.yaml -o %t/foo.o
+# RUN: llvm-libtool-darwin -static -o %t/libfirst.a %t/foo.o -dependency_info %t/simple.dat
+# RUN: %python %S/Inputs/DependencyDump.py %t/simple.dat | FileCheck --check-prefix=SIMPLE %s
+
+# RUN: llvm-libtool-darwin -static -o %t/second.lib %t/foo.o -lfirst -L/missing/directory/without/lib -L%t -dependency_info %t/lib.dat
+# RUN: %python %S/Inputs/DependencyDump.py %t/lib.dat | FileCheck --check-prefix=LIB %s
+
+# SIMPLE: version: llvm-libtool-darwin
+# SIMPLE: input-file: {{.+}}foo.o
+# SIMPLE: output-file: {{.+}}libfirst.a
+
+# LIB: version: llvm-libtool-darwin
+# LIB: input-file: {{.+}}foo.o
+# LIB: input-file: {{.+}}libfirst.a
+# LIB: not-found: {{.+}}missing{{.+}}directory{{.+}}without{{.+}}lib{{.+}}libfirst.a
+# LIB: output-file: {{.+}}second.lib

diff  --git a/llvm/tools/llvm-libtool-darwin/DependencyInfo.h b/llvm/tools/llvm-libtool-darwin/DependencyInfo.h
new file mode 100644
index 0000000000000..7b2f94bdbeb81
--- /dev/null
+++ b/llvm/tools/llvm-libtool-darwin/DependencyInfo.h
@@ -0,0 +1,85 @@
+//===-- DependencyInfo.h --------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <set>
+
+class DependencyInfo {
+public:
+  explicit DependencyInfo(std::string DependencyInfoPath)
+      : DependencyInfoPath(DependencyInfoPath) {}
+
+  virtual ~DependencyInfo(){};
+
+  virtual void addMissingInput(llvm::StringRef Path) {
+    NotFounds.insert(Path.str());
+  }
+
+  // Writes the dependencies to specified path. The content is first sorted by
+  // OpCode and then by the filename (in alphabetical order).
+  virtual void write(llvm::Twine Version,
+                     const std::vector<std::string> &Inputs,
+                     std::string Output) {
+    std::error_code EC;
+    llvm::raw_fd_ostream OS(DependencyInfoPath, EC, llvm::sys::fs::OF_None);
+    if (EC) {
+      llvm::WithColor::defaultErrorHandler(llvm::createStringError(
+          EC,
+          "failed to write to " + DependencyInfoPath + ": " + EC.message()));
+      return;
+    }
+
+    auto AddDep = [&OS](DependencyInfoOpcode Opcode,
+                        const llvm::StringRef &Path) {
+      OS << static_cast<uint8_t>(Opcode);
+      OS << Path;
+      OS << '\0';
+    };
+
+    AddDep(DependencyInfoOpcode::Tool, Version.str());
+
+    // Sort the input by its names.
+    std::vector<llvm::StringRef> InputNames;
+    InputNames.reserve(Inputs.size());
+    for (const auto &F : Inputs)
+      InputNames.push_back(F);
+    llvm::sort(InputNames);
+
+    for (const auto &In : InputNames)
+      AddDep(DependencyInfoOpcode::InputFound, In);
+
+    for (const std::string &F : NotFounds)
+      AddDep(DependencyInfoOpcode::InputMissing, F);
+
+    AddDep(DependencyInfoOpcode::Output, Output);
+  }
+
+private:
+  enum DependencyInfoOpcode : uint8_t {
+    Tool = 0x00,
+    InputFound = 0x10,
+    InputMissing = 0x11,
+    Output = 0x40,
+  };
+
+  const std::string DependencyInfoPath;
+  std::set<std::string> NotFounds;
+};
+
+// Subclass to avoid any overhead when not using this feature
+class DummyDependencyInfo : public DependencyInfo {
+public:
+  DummyDependencyInfo() : DependencyInfo("") {}
+  void addMissingInput(llvm::StringRef Path) override {}
+  void write(llvm::Twine Version, const std::vector<std::string> &Inputs,
+             std::string Output) override {}
+};

diff  --git a/llvm/tools/llvm-libtool-darwin/llvm-libtool-darwin.cpp b/llvm/tools/llvm-libtool-darwin/llvm-libtool-darwin.cpp
index 8d4529cddf365..5fec8475f5eef 100644
--- a/llvm/tools/llvm-libtool-darwin/llvm-libtool-darwin.cpp
+++ b/llvm/tools/llvm-libtool-darwin/llvm-libtool-darwin.cpp
@@ -10,6 +10,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "DependencyInfo.h"
 #include "llvm/BinaryFormat/Magic.h"
 #include "llvm/IR/LLVMContext.h"
 #include "llvm/Object/ArchiveWriter.h"
@@ -87,6 +88,12 @@ static cl::list<std::string> LibrarySearchDirs(
         " libraries"),
     cl::Prefix, cl::cat(LibtoolCategory));
 
+static cl::opt<std::string> DependencyInfoPath(
+    "dependency_info",
+    cl::desc("Write an Xcode dependency info file describing the dependencies "
+             "of the created library"),
+    cl::cat(LibtoolCategory));
+
 static cl::opt<bool>
     VersionOption("V", cl::desc("Print the version number and exit"),
                   cl::cat(LibtoolCategory));
@@ -109,6 +116,8 @@ static const std::array<std::string, 3> StandardSearchDirs{
     "/usr/local/lib",
 };
 
+std::unique_ptr<DependencyInfo> GlobalDependencyInfo;
+
 struct Config {
   bool Deterministic = true; // Updated by 'D' and 'U' modifiers.
   uint32_t ArchCPUType;
@@ -116,7 +125,6 @@ struct Config {
 };
 
 static Expected<std::string> searchForFile(const Twine &FileName) {
-
   auto FindLib =
       [FileName](ArrayRef<std::string> SearchDirs) -> Optional<std::string> {
     for (StringRef Dir : SearchDirs) {
@@ -125,6 +133,8 @@ static Expected<std::string> searchForFile(const Twine &FileName) {
 
       if (sys::fs::exists(Path))
         return std::string(Path);
+
+      GlobalDependencyInfo->addMissingInput(Path);
     }
     return None;
   };
@@ -652,6 +662,11 @@ static Expected<Config> parseCommandLine(int Argc, char **Argv) {
     return C;
   }
 
+  GlobalDependencyInfo =
+      DependencyInfoPath.empty()
+          ? std::make_unique<DummyDependencyInfo>()
+          : std::make_unique<DependencyInfo>(DependencyInfoPath);
+
   if (OutputFile.empty()) {
     std::string Error;
     raw_string_ostream Stream(Error);
@@ -686,6 +701,9 @@ static Expected<Config> parseCommandLine(int Argc, char **Argv) {
             MachO::getArchitectureFromName(ArchType));
   }
 
+  GlobalDependencyInfo->write("llvm-libtool-darwin " LLVM_VERSION_STRING,
+                              InputFiles, OutputFile);
+
   return C;
 }
 


        


More information about the llvm-commits mailing list