--- /dev/null
+#
+# 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()
--- /dev/null
+## 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
--- /dev/null
+//===-- 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 {}
+};
//
//===----------------------------------------------------------------------===//
+#include "DependencyInfo.h"
#include "llvm/BinaryFormat/Magic.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/Object/ArchiveWriter.h"
" 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));
"/usr/local/lib",
};
+std::unique_ptr<DependencyInfo> GlobalDependencyInfo;
+
struct Config {
bool Deterministic = true; // Updated by 'D' and 'U' modifiers.
uint32_t ArchCPUType;
};
static Expected<std::string> searchForFile(const Twine &FileName) {
-
auto FindLib =
[FileName](ArrayRef<std::string> SearchDirs) -> Optional<std::string> {
for (StringRef Dir : SearchDirs) {
if (sys::fs::exists(Path))
return std::string(Path);
+
+ GlobalDependencyInfo->addMissingInput(Path);
}
return None;
};
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);
MachO::getArchitectureFromName(ArchType));
}
+ GlobalDependencyInfo->write("llvm-libtool-darwin " LLVM_VERSION_STRING,
+ InputFiles, OutputFile);
+
return C;
}