Ninja: Make cmcldeps depfile output more consistent with 'ninja -t msvc'

Ninja relies on the generator to produce paths that match up with the
paths used in the build.ninja file, which are spelled with backslashes.
Therefore, cmcldeps should canonicalize depfile paths to use backslashes
and relativize paths to the build directory.
This commit is contained in:
Reid Kleckner 2013-05-23 15:13:55 -04:00 committed by Brad King
parent ffe79b582f
commit 6fa9d0ab40
1 changed files with 24 additions and 9 deletions

View File

@ -62,8 +62,8 @@ static std::string trimLeadingSpace(const std::string& cmdline) {
return cmdline.substr(i); return cmdline.substr(i);
} }
static void doEscape(std::string& str, const std::string& search, static void replaceAll(std::string& str, const std::string& search,
const std::string& repl) { const std::string& repl) {
std::string::size_type pos = 0; std::string::size_type pos = 0;
while ((pos = str.find(search, pos)) != std::string::npos) { while ((pos = str.find(search, pos)) != std::string::npos) {
str.replace(pos, search.size(), repl); str.replace(pos, search.size(), repl);
@ -71,6 +71,10 @@ static void doEscape(std::string& str, const std::string& search,
} }
} }
bool startsWith(const std::string& str, const std::string& what) {
return str.compare(0, what.size(), what) == 0;
}
// Strips one argument from the cmdline and returns it. "surrounding quotes" // Strips one argument from the cmdline and returns it. "surrounding quotes"
// are removed from the argument if there were any. // are removed from the argument if there were any.
static std::string getArg(std::string& cmdline) { static std::string getArg(std::string& cmdline) {
@ -117,6 +121,13 @@ static void parseCommandLine(LPTSTR wincmdline,
rest = trimLeadingSpace(cmdline); rest = trimLeadingSpace(cmdline);
} }
// Not all backslashes need to be escaped in a depfile, but it's easier that
// way. See the re2c grammar in ninja's source code for more info.
static void escapePath(std::string &path) {
replaceAll(path, "\\", "\\\\");
replaceAll(path, " ", "\\ ");
}
static void outputDepFile(const std::string& dfile, const std::string& objfile, static void outputDepFile(const std::string& dfile, const std::string& objfile,
std::vector<std::string>& incs) { std::vector<std::string>& incs) {
@ -132,16 +143,24 @@ static void outputDepFile(const std::string& dfile, const std::string& objfile,
// FIXME should this be fatal or not? delete obj? delete d? // FIXME should this be fatal or not? delete obj? delete d?
if (!out) if (!out)
return; return;
std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
replaceAll(cwd, "/", "\\");
cwd += "\\";
std::string tmp = objfile; std::string tmp = objfile;
doEscape(tmp, " ", "\\ "); escapePath(tmp);
fprintf(out, "%s: \\\n", tmp.c_str()); fprintf(out, "%s: \\\n", tmp.c_str());
std::vector<std::string>::iterator it = incs.begin(); std::vector<std::string>::iterator it = incs.begin();
for (; it != incs.end(); ++it) { for (; it != incs.end(); ++it) {
tmp = *it; tmp = *it;
doEscape(tmp, "\\", "/"); // The paths need to match the ones used to identify build artifacts in the
doEscape(tmp, " ", "\\ "); // build.ninja file. Therefore we need to canonicalize the path to use
// backward slashes and relativize the path to the build directory.
replaceAll(tmp, "/", "\\");
if (startsWith(tmp, cwd))
tmp = tmp.substr(cwd.size());
escapePath(tmp);
fprintf(out, "%s \\\n", tmp.c_str()); fprintf(out, "%s \\\n", tmp.c_str());
} }
@ -150,10 +169,6 @@ static void outputDepFile(const std::string& dfile, const std::string& objfile,
} }
bool startsWith(const std::string& str, const std::string& what) {
return str.compare(0, what.size(), what) == 0;
}
bool contains(const std::string& str, const std::string& what) { bool contains(const std::string& str, const std::string& what) {
return str.find(what) != std::string::npos; return str.find(what) != std::string::npos;
} }