#include "lld/Common/ErrorHandler.h"
#include "llvm/ADT/MapVector.h"
+#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/BinaryFormat/ELF.h"
uint8_t osabi = 0;
uint32_t andFeatures = 0;
llvm::CachePruningPolicy thinLTOCachePolicy;
+ llvm::SetVector<StringRef> dependencyFiles; // for --dependency-file
llvm::StringMap<uint64_t> sectionStartMap;
llvm::StringRef bfdname;
llvm::StringRef chroot;
- llvm::StringRef dynamicLinker;
+ llvm::StringRef dependencyFile;
llvm::StringRef dwoDir;
+ llvm::StringRef dynamicLinker;
llvm::StringRef entry;
llvm::StringRef emulation;
llvm::StringRef fini;
config->optimizeBBJumps =
args.hasFlag(OPT_optimize_bb_jumps, OPT_no_optimize_bb_jumps, false);
config->demangle = args.hasFlag(OPT_demangle, OPT_no_demangle, true);
+ config->dependencyFile = args.getLastArgValue(OPT_dependency_file);
config->dependentLibraries = args.hasFlag(OPT_dependent_libraries, OPT_no_dependent_libraries, true);
config->disableVerify = args.hasArg(OPT_disable_verify);
config->discard = getDiscard(args);
sym->fetch();
}
+// Handle --dependency-file=<path>. If that option is given, lld creates a
+// file at a given path with the following contents:
+//
+// <output-file>: <input-file> ...
+//
+// <input-file>:
+//
+// where <output-file> is a pathname of an output file and <input-file>
+// ... is a list of pathnames of all input files. `make` command can read a
+// file in the above format and interpret it as a dependency info. We write
+// phony targets for every <input-file> to avoid an error when that file is
+// removed.
+//
+// This option is useful if you want to make your final executable to depend
+// on all input files including system libraries. Here is why.
+//
+// When you write a Makefile, you usually write it so that the final
+// executable depends on all user-generated object files. Normally, you
+// don't make your executable to depend on system libraries (such as libc)
+// because you don't know the exact paths of libraries, even though system
+// libraries that are linked to your executable statically are technically a
+// part of your program. By using --dependency-file option, you can make
+// lld to dump dependency info so that you can maintain exact dependencies
+// easily.
+static void writeDependencyFile() {
+ std::error_code ec;
+ raw_fd_ostream os(config->dependencyFile, ec, sys::fs::F_None);
+ if (ec) {
+ error("cannot open " + config->dependencyFile + ": " + ec.message());
+ return;
+ }
+
+ // We use the same escape rules as Clang/GCC which are accepted by Make/Ninja:
+ // * A space is escaped by a backslash which itself must be escaped.
+ // * A hash sign is escaped by a single backslash.
+ // * $ is escapes as $$.
+ auto printFilename = [](raw_fd_ostream &os, StringRef filename) {
+ llvm::SmallString<256> nativePath;
+ llvm::sys::path::native(filename.str(), nativePath);
+ llvm::sys::path::remove_dots(nativePath, /*remove_dot_dot=*/true);
+ for (unsigned i = 0, e = nativePath.size(); i != e; ++i) {
+ if (nativePath[i] == '#') {
+ os << '\\';
+ } else if (nativePath[i] == ' ') {
+ os << '\\';
+ unsigned j = i;
+ while (j > 0 && nativePath[--j] == '\\')
+ os << '\\';
+ } else if (nativePath[i] == '$') {
+ os << '$';
+ }
+ os << nativePath[i];
+ }
+ };
+
+ os << config->outputFile << ":";
+ for (StringRef path : config->dependencyFiles) {
+ os << " \\\n ";
+ printFilename(os, path);
+ }
+ os << "\n";
+
+ for (StringRef path : config->dependencyFiles) {
+ os << "\n";
+ printFilename(os, path);
+ os << ":\n";
+ }
+}
+
// Replaces common symbols with defined symbols reside in .bss sections.
// This function is called after all symbol names are resolved. As a
// result, the passes after the symbol resolution won't see any
return false;
});
+ // Since we now have a complete set of input files, we can create
+ // a .d file to record build dependencies.
+ if (!config->dependencyFile.empty())
+ writeDependencyFile();
+
// Now that the number of partitions is fixed, save a pointer to the main
// partition.
mainPart = &partitions[0];
--- /dev/null
+# REQUIRES: x86
+# RUN: mkdir -p %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t/foo.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64 /dev/null -o "%t/bar baz.o"
+# RUN: llvm-mc -filetype=obj -triple=x86_64 /dev/null -o "%t/#quux$.o"
+# RUN: ld.lld -o %t/foo.exe %t/foo.o %t/"bar baz.o" "%t/#quux$.o" --dependency-file=%t/foo.d
+# RUN: FileCheck --match-full-lines -DFILE=%t %s < %t/foo.d
+
+# CHECK: [[FILE]]{{/|\\\\}}foo.exe: \
+# CHECK-NEXT: [[FILE]]{{/|\\\\}}foo.o \
+# CHECK-NEXT: [[FILE]]{{/|\\\\}}bar\ baz.o \
+# CHECK-NEXT: [[FILE]]{{/|\\\\}}\#quux$$.o
+# CHECK-EMPTY:
+# CHECK-NEXT: [[FILE]]{{/|\\\\}}foo.o:
+# CHECK-EMPTY:
+# CHECK-NEXT: [[FILE]]{{/|\\\\}}bar\ baz.o:
+# CHECK-EMPTY:
+# CHECK-NEXT: [[FILE]]{{/|\\\\}}\#quux$$.o:
+
+.global _start
+_start: