From: Daniel Dunbar Date: Mon, 30 Mar 2009 00:34:04 +0000 (+0000) Subject: Improve dependency file support. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a5a7bd0de7b6b80212095195a055a4a43f21d4b2;p=clang Improve dependency file support. - Rip out various bits of logic from clang-cc's dependency file gen, force driver to provide instead. - -MD output now goes to proper location clang -MD puts dep file in /tmp with wrong name - -M and -MM still don't work correctly. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@68022 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index 2f7c464bbf..bd833ead27 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -210,14 +210,58 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // FIXME: Add --stack-protector-buffer-size= on // -fstack-protect. - Args.AddLastArg(CmdArgs, options::OPT_MD); - Args.AddLastArg(CmdArgs, options::OPT_MMD); - Args.AddAllArgs(CmdArgs, options::OPT_MF); + // Handle dependency file generation. + Arg *A; + if ((A = Args.getLastArg(options::OPT_M)) || + (A = Args.getLastArg(options::OPT_MM)) || + (A = Args.getLastArg(options::OPT_MD)) || + (A = Args.getLastArg(options::OPT_MMD))) { + // Determine the output location. + const char *DepFile; + if (Arg *MF = Args.getLastArg(options::OPT_MF)) { + DepFile = MF->getValue(Args); + } else if (A->getOption().getId() == options::OPT_M || + A->getOption().getId() == options::OPT_MM) { + DepFile = "-"; + } else { + DepFile = darwin::CC1::getDependencyFileName(Args, Inputs); + } + CmdArgs.push_back("-dependency-file"); + CmdArgs.push_back(DepFile); + + // Add an -MT option if the user didn't specify their own. + // FIXME: This should use -MQ, when we support it. + if (!Args.hasArg(options::OPT_MT) && !Args.hasArg(options::OPT_MQ)) { + const char *DepTarget; + + // If user provided -o, that is the dependency target. + if (Arg *A = Args.getLastArg(options::OPT_o)) { + DepTarget = A->getValue(Args); + } else { + // Otherwise derive from the base input. + // + // FIXME: This should use the computed output file location. + llvm::sys::Path P(Inputs[0].getBaseInput()); + + P.eraseSuffix(); + P.appendSuffix("o"); + DepTarget = Args.MakeArgString(P.getLast().c_str()); + } + + CmdArgs.push_back("-MT"); + CmdArgs.push_back(DepTarget); + } + + if (A->getOption().getId() == options::OPT_M || + A->getOption().getId() == options::OPT_MD) + CmdArgs.push_back("-sys-header-deps"); + } + Args.AddLastArg(CmdArgs, options::OPT_MP); Args.AddAllArgs(CmdArgs, options::OPT_MT); Arg *Unsupported = Args.getLastArg(options::OPT_M); - if (!Unsupported) + if (!Unsupported) Unsupported = Args.getLastArg(options::OPT_MM); if (!Unsupported) Unsupported = Args.getLastArg(options::OPT_MG); @@ -327,7 +371,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-arch"); CmdArgs.push_back(getToolChain().getArchName().c_str()); - if (Output.isPipe()) { + // FIXME: We should have a separate type for this. + if (Args.hasArg(options::OPT_M) || Args.hasArg(options::OPT_MM)) { + CmdArgs.push_back("-M"); + } else if (Output.isPipe()) { CmdArgs.push_back("-o"); CmdArgs.push_back("-"); } else if (Output.isFilename()) { @@ -478,13 +525,13 @@ const char *darwin::CC1::getCC1Name(types::ID Type) const { } const char *darwin::CC1::getBaseInputName(const ArgList &Args, - const InputInfoList &Inputs) const { + const InputInfoList &Inputs) { llvm::sys::Path P(Inputs[0].getBaseInput()); return Args.MakeArgString(P.getLast().c_str()); } const char *darwin::CC1::getBaseInputStem(const ArgList &Args, - const InputInfoList &Inputs) const { + const InputInfoList &Inputs) { const char *Str = getBaseInputName(Args, Inputs); if (const char *End = strchr(Str, '.')) @@ -495,7 +542,7 @@ const char *darwin::CC1::getBaseInputStem(const ArgList &Args, const char * darwin::CC1::getDependencyFileName(const ArgList &Args, - const InputInfoList &Inputs) const { + const InputInfoList &Inputs) { // FIXME: Think about this more. std::string Res; @@ -504,7 +551,7 @@ darwin::CC1::getDependencyFileName(const ArgList &Args, Res = Str.substr(0, Str.rfind('.')); } else - Res = getBaseInputStem(Args, Inputs); + Res = darwin::CC1::getBaseInputStem(Args, Inputs); return Args.MakeArgString((Res + ".d").c_str()); } @@ -558,7 +605,7 @@ void darwin::CC1::AddCC1OptionsArgs(const ArgList &Args, ArgStringList &CmdArgs, CmdArgs.push_back("-quiet"); CmdArgs.push_back("-dumpbase"); - CmdArgs.push_back(getBaseInputName(Args, Inputs)); + CmdArgs.push_back(darwin::CC1::getBaseInputName(Args, Inputs)); Args.AddAllArgs(CmdArgs, options::OPT_d_Group); @@ -575,7 +622,7 @@ void darwin::CC1::AddCC1OptionsArgs(const ArgList &Args, ArgStringList &CmdArgs, CmdArgs.push_back(OutputOpt->getValue(Args)); } else { CmdArgs.push_back("-auxbase"); - CmdArgs.push_back(getBaseInputStem(Args, Inputs)); + CmdArgs.push_back(darwin::CC1::getBaseInputStem(Args, Inputs)); } Args.AddAllArgs(CmdArgs, options::OPT_g_Group); @@ -686,12 +733,12 @@ void darwin::CC1::AddCPPUniqueOptionsArgs(const ArgList &Args, if (Args.hasArg(options::OPT_MD)) { CmdArgs.push_back("-MD"); - CmdArgs.push_back(getDependencyFileName(Args, Inputs)); + CmdArgs.push_back(darwin::CC1::getDependencyFileName(Args, Inputs)); } if (Args.hasArg(options::OPT_MMD)) { CmdArgs.push_back("-MMD"); - CmdArgs.push_back(getDependencyFileName(Args, Inputs)); + CmdArgs.push_back(darwin::CC1::getDependencyFileName(Args, Inputs)); } Args.AddLastArg(CmdArgs, options::OPT_M); diff --git a/lib/Driver/Tools.h b/lib/Driver/Tools.h index cbe7e99061..7ad60ed10c 100644 --- a/lib/Driver/Tools.h +++ b/lib/Driver/Tools.h @@ -117,14 +117,16 @@ namespace gcc { namespace darwin { class VISIBILITY_HIDDEN CC1 : public Tool { + public: + static const char *getBaseInputName(const ArgList &Args, + const InputInfoList &Input); + static const char *getBaseInputStem(const ArgList &Args, + const InputInfoList &Input); + static const char *getDependencyFileName(const ArgList &Args, + const InputInfoList &Inputs); + protected: const char *getCC1Name(types::ID Type) const; - const char *getBaseInputName(const ArgList &Args, - const InputInfoList &Input) const; - const char *getBaseInputStem(const ArgList &Args, - const InputInfoList &Input) const; - const char *getDependencyFileName(const ArgList &Args, - const InputInfoList &Inputs) const; void AddCC1Args(const ArgList &Args, ArgStringList &CmdArgs) const; void AddCC1OptionsArgs(const ArgList &Args, ArgStringList &CmdArgs, diff --git a/test/Frontend/dependency-gen.c b/test/Frontend/dependency-gen.c index ea95e0601b..a9ee63708c 100644 --- a/test/Frontend/dependency-gen.c +++ b/test/Frontend/dependency-gen.c @@ -1,5 +1,5 @@ - // rdar://6533411 -// RUN: clang-cc -MD -MF %t.d -x c /dev/null - +// RUN: clang -MD -MF %t.d -c -x c -o %t.o /dev/null && +// RUN: grep '.*dependency-gen.c.out.tmp.o:' %t.d +// RUN: grep '/dev/null' %t.d diff --git a/tools/clang-cc/DependencyFile.cpp b/tools/clang-cc/DependencyFile.cpp index 2140afcfef..518f167305 100644 --- a/tools/clang-cc/DependencyFile.cpp +++ b/tools/clang-cc/DependencyFile.cpp @@ -23,7 +23,6 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/raw_ostream.h" -#include #include using namespace clang; @@ -33,9 +32,8 @@ class VISIBILITY_HIDDEN DependencyFileCallback : public PPCallbacks { std::vector Files; llvm::StringSet<> FilesSet; const Preprocessor *PP; - std::ofstream OS; - const std::string &InputFile; std::vector Targets; + llvm::raw_ostream *OS; private: bool FileMatchesDepCriteria(const char *Filename, @@ -43,36 +41,33 @@ private: void OutputDependencyFile(); public: - DependencyFileCallback(const Preprocessor *PP, - const std::string &InputFile, - const std::string &DepFile, - const std::vector &Targets, - const char *&ErrStr); - ~DependencyFileCallback(); + DependencyFileCallback(const Preprocessor *_PP, + llvm::raw_ostream *_OS, + const std::vector &_Targets) + : PP(_PP), Targets(_Targets), OS(_OS) { + } + + ~DependencyFileCallback() { + OutputDependencyFile(); + OS->flush(); + delete OS; + } + virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason, SrcMgr::CharacteristicKind FileType); }; } -static const char *DependencyFileExt = "d"; -static const char *ObjectFileExt = "o"; - //===----------------------------------------------------------------------===// // Dependency file options //===----------------------------------------------------------------------===// -static llvm::cl::opt -GenerateDependencyFile("MD", - llvm::cl::desc("Generate dependency for main source file " - "(system headers included)")); +static llvm::cl::opt +DependencyFile("dependency-file", + llvm::cl::desc("Filename (or -) to write dependency output to")); static llvm::cl::opt -GenerateDependencyFileNoSysHeaders("MMD", - llvm::cl::desc("Generate dependency for main source file " - "(no system headers)")); - -static llvm::cl::opt -DependencyOutputFile("MF", - llvm::cl::desc("Specify dependency output file")); +DependenciesIncludeSystemHeaders("sys-header-deps", + llvm::cl::desc("Include system headers in dependency output")); static llvm::cl::list DependencyTargets("MT", @@ -85,82 +80,41 @@ PhonyDependencyTarget("MP", "(other than main file)")); bool clang::CreateDependencyFileGen(Preprocessor *PP, - std::string &OutputFile, - const std::string &InputFile, - const char *&ErrStr) { - assert(!InputFile.empty() && "No file given"); - - ErrStr = NULL; - - if (!GenerateDependencyFile && !GenerateDependencyFileNoSysHeaders) { - if (!DependencyOutputFile.empty() || !DependencyTargets.empty() || - PhonyDependencyTarget) - ErrStr = "Error: to generate dependencies you must specify -MD or -MMD\n"; + std::string &ErrStr) { + ErrStr = ""; + if (DependencyFile.empty()) return false; - } - - // Handle conflicting options - if (GenerateDependencyFileNoSysHeaders) - GenerateDependencyFile = false; - // Determine name of dependency output filename - llvm::sys::Path DepFile; - if (!DependencyOutputFile.empty()) - DepFile = DependencyOutputFile; - else if (!OutputFile.empty()) { - DepFile = OutputFile; - DepFile.eraseSuffix(); - DepFile.appendSuffix(DependencyFileExt); - } - else { - DepFile = InputFile; - DepFile.eraseSuffix(); - DepFile.appendSuffix(DependencyFileExt); + if (DependencyTargets.empty()) { + ErrStr = "-dependency-file requires at least one -MT option\n"; + return false; } - std::vector Targets(DependencyTargets); - - // Infer target name if unspecified - if (Targets.empty()) { - if (!OutputFile.empty()) { - llvm::sys::Path TargetPath(OutputFile); - TargetPath.eraseSuffix(); - TargetPath.appendSuffix(ObjectFileExt); - Targets.push_back(TargetPath.toString()); - } else { - llvm::sys::Path TargetPath(InputFile); - TargetPath.eraseSuffix(); - TargetPath.appendSuffix(ObjectFileExt); - Targets.push_back(TargetPath.toString()); - } + std::string ErrMsg; + llvm::raw_ostream *OS = + new llvm::raw_fd_ostream(DependencyFile.c_str(), false, ErrStr); + if (!ErrMsg.empty()) { + ErrStr = "unable to open dependency file: " + ErrMsg; + return false; } DependencyFileCallback *PPDep = - new DependencyFileCallback(PP, InputFile, DepFile.toString(), - Targets, ErrStr); - if (ErrStr){ - delete PPDep; - return false; - } - else { - PP->setPPCallbacks(PPDep); - return true; - } + new DependencyFileCallback(PP, OS, DependencyTargets); + PP->setPPCallbacks(PPDep); + return true; } /// FileMatchesDepCriteria - Determine whether the given Filename should be /// considered as a dependency. bool DependencyFileCallback::FileMatchesDepCriteria(const char *Filename, SrcMgr::CharacteristicKind FileType) { - if (strcmp(InputFile.c_str(), Filename) != 0 && - strcmp("", Filename) != 0) { - if (GenerateDependencyFileNoSysHeaders) - return FileType == SrcMgr::C_User; - else - return true; - } + if (strcmp("", Filename) == 0) + return false; + + if (DependenciesIncludeSystemHeaders) + return true; - return false; + return FileType == SrcMgr::C_User; } void DependencyFileCallback::FileChanged(SourceLocation Loc, @@ -169,9 +123,9 @@ void DependencyFileCallback::FileChanged(SourceLocation Loc, if (Reason != PPCallbacks::EnterFile) return; - // Depedency generation really does want to go all the way to the file entry - // for a source location to find out what is depended on. We do not want - // #line markers to affect dependency generation! + // Dependency generation really does want to go all the way to the + // file entry for a source location to find out what is depended on. + // We do not want #line markers to affect dependency generation! SourceManager &SM = PP->getSourceManager(); const FileEntry *FE = @@ -203,17 +157,17 @@ void DependencyFileCallback::OutputDependencyFile() { unsigned N = I->length(); if (Columns == 0) { Columns += N; - OS << *I; + *OS << *I; } else if (Columns + N + 2 > MaxColumns) { Columns = N + 2; - OS << " \\\n " << *I; + *OS << " \\\n " << *I; } else { Columns += N + 1; - OS << " " << *I; + *OS << ' ' << *I; } } - OS << ":"; + *OS << ':'; Columns += 1; // Now add each dependency in the order it was seen, but avoiding @@ -225,48 +179,22 @@ void DependencyFileCallback::OutputDependencyFile() { // break the line on the next iteration. unsigned N = I->length(); if (Columns + (N + 1) + 2 > MaxColumns) { - OS << " \\\n "; + *OS << " \\\n "; Columns = 2; } - OS << " " << *I; + *OS << ' ' << *I; Columns += N + 1; } - OS << "\n"; + *OS << '\n'; // Create phony targets if requested. if (PhonyDependencyTarget) { // Skip the first entry, this is always the input file itself. for (std::vector::iterator I = Files.begin() + 1, E = Files.end(); I != E; ++I) { - OS << "\n"; - OS << *I << ":\n"; + *OS << '\n'; + *OS << *I << ":\n"; } } } -DependencyFileCallback::DependencyFileCallback(const Preprocessor *PP, - const std::string &InputFile, - const std::string &DepFile, - const std::vector - &Targets, - const char *&ErrStr) - : PP(PP), InputFile(InputFile), Targets(Targets) { - - OS.open(DepFile.c_str()); - if (OS.fail()) - ErrStr = "Could not open dependency output file\n"; - else - ErrStr = NULL; - - Files.push_back(InputFile); -} - -DependencyFileCallback::~DependencyFileCallback() { - if ((!GenerateDependencyFile && !GenerateDependencyFileNoSysHeaders) || - OS.fail()) - return; - - OutputDependencyFile(); - OS.close(); -} - diff --git a/tools/clang-cc/clang.cpp b/tools/clang-cc/clang.cpp index 5b1e6ab62d..7541f80883 100644 --- a/tools/clang-cc/clang.cpp +++ b/tools/clang-cc/clang.cpp @@ -1197,11 +1197,11 @@ public: } /// FIXME: PP can only handle one callback - if (ProgAction != PrintPreprocessedInput) { - const char* ErrStr; - bool DFG = CreateDependencyFileGen(PP.get(), OutputFile, InFile, ErrStr); - if (!DFG && ErrStr) { - fprintf(stderr, "%s", ErrStr); + if (ProgAction != PrintPreprocessedInput) { + std::string ErrStr; + bool DFG = CreateDependencyFileGen(PP.get(), ErrStr); + if (!DFG && !ErrStr.empty()) { + fprintf(stderr, "%s", ErrStr.c_str()); return NULL; } } diff --git a/tools/clang-cc/clang.h b/tools/clang-cc/clang.h index 33bc7fe583..1e39897d0f 100644 --- a/tools/clang-cc/clang.h +++ b/tools/clang-cc/clang.h @@ -50,10 +50,7 @@ bool CheckDiagnostics(Preprocessor &PP); /// CreateDependencyFileGen - Create dependency file generator. /// This is only done if either -MD or -MMD has been specified. -bool CreateDependencyFileGen(Preprocessor *PP, - std::string &OutputFile, - const std::string &InputFile, - const char *&ErrStr); +bool CreateDependencyFileGen(Preprocessor *PP, std::string &ErrStr); /// CacheTokens - Cache tokens for use with PCH. void CacheTokens(Preprocessor& PP, const std::string& OutFile);