diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -11,6 +11,7 @@ #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" @@ -83,6 +84,7 @@ uint8_t osabi = 0; uint32_t andFeatures = 0; llvm::CachePruningPolicy thinLTOCachePolicy; + llvm::SetVector dependencyFiles; // for --write-dependencies llvm::StringMap sectionStartMap; llvm::StringRef chroot; llvm::StringRef dynamicLinker; @@ -107,6 +109,7 @@ llvm::StringRef sysroot; llvm::StringRef thinLTOCacheDir; llvm::StringRef thinLTOIndexOnlyArg; + llvm::StringRef writeDependencies; std::pair thinLTOObjectSuffixReplace; std::pair thinLTOPrefixReplace; std::string rpath; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -917,6 +917,7 @@ args.hasFlag(OPT_warn_ifunc_textrel, OPT_no_warn_ifunc_textrel, false); config->warnSymbolOrdering = args.hasFlag(OPT_warn_symbol_ordering, OPT_no_warn_symbol_ordering, true); + config->writeDependencies = args.getLastArgValue(OPT_write_dependencies); config->zCombreloc = getZFlag(args, "combreloc", "nocombreloc", true); config->zCopyreloc = getZFlag(args, "copyreloc", "nocopyreloc", true); config->zExecstack = getZFlag(args, "execstack", "noexecstack", false); @@ -1373,6 +1374,45 @@ sym->fetch(); } +// Handle --write-dependencies=. If that option is given, lld creates a +// file at a given path with the following contents: +// +// : ... +// +// where is a pathname of an output file and +// ... 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. +// +// 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 +// statically-linked system libraries are technically a part of your +// program. By using --write-dependencies option, you can make lld to dump +// dependency info so that you can maintain exact dependencies easily. +static void writeFileDependencies() { + std::error_code ec; + raw_fd_ostream os(config->writeDependencies, ec, sys::fs::F_None); + if (ec) { + error("cannot open " + config->writeDependencies + ": " + ec.message()); + return; + } + + os << config->outputFile << ":"; + for (StringRef path : config->dependencyFiles) { + SmallString<128> s = path; + sys::path::remove_dots(s, /*remove_dot_dot=*/true); + if (s.str().contains(' ')) + os << " \\\n \"" << s << '"'; + else + os << " \\\n " << s; + } + 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 @@ -1842,6 +1882,11 @@ (s->name.startswith(".debug") || s->name.startswith(".zdebug")); }); + // Since we now have a complete set of input files, we can create + // a .d file to record build dependencies. + if (!config->writeDependencies.empty()) + writeFileDependencies(); + // Now that the number of partitions is fixed, save a pointer to the main // partition. mainPart = &partitions[0]; diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -95,6 +95,7 @@ path = saver.save(config->chroot + path); log(path); + config->dependencyFiles.insert(path); auto mbOrErr = MemoryBuffer::getFile(path, -1, false); if (auto ec = mbOrErr.getError()) { diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td --- a/lld/ELF/Options.td +++ b/lld/ELF/Options.td @@ -413,6 +413,9 @@ defm wrap: Eq<"wrap", "Use wrapper functions for symbol">, MetaVarName<"=">; +defm write_dependencies: Eq<"write-dependencies", "Write a dep file">, + MetaVarName<"">; + def z: JoinedOrSeparate<["-"], "z">, MetaVarName<"