Ninja: extract dependencies for .rc files with msvc tools
rc.exe doesn't support /showIncludes. Because .rc files also #include stuff we can misuse cl.exe to get the included files. Done one the fly by cmcldeps.
This commit is contained in:
parent
43200c145d
commit
54a388beaa
|
@ -339,7 +339,7 @@ cmNinjaTargetGenerator
|
||||||
bool useClDeps = false;
|
bool useClDeps = false;
|
||||||
std::string clDepsBinary;
|
std::string clDepsBinary;
|
||||||
std::string clShowPrefix;
|
std::string clShowPrefix;
|
||||||
if (lang == "C" || lang == "CXX")
|
if (lang == "C" || lang == "CXX" || lang == "RC")
|
||||||
{
|
{
|
||||||
const char* depsPtr = mf->GetDefinition("CMAKE_CMCLDEPS_EXECUTABLE");
|
const char* depsPtr = mf->GetDefinition("CMAKE_CMCLDEPS_EXECUTABLE");
|
||||||
const char* showPtr = mf->GetDefinition("CMAKE_CL_SHOWINCLUDE_PREFIX");
|
const char* showPtr = mf->GetDefinition("CMAKE_CL_SHOWINCLUDE_PREFIX");
|
||||||
|
@ -352,8 +352,9 @@ cmNinjaTargetGenerator
|
||||||
if (projectName != "CMAKE_TRY_COMPILE")
|
if (projectName != "CMAKE_TRY_COMPILE")
|
||||||
{
|
{
|
||||||
useClDeps = true;
|
useClDeps = true;
|
||||||
clDepsBinary = depsPtr;
|
std::string qu = "\"";
|
||||||
clShowPrefix = showPtr;
|
clDepsBinary = qu + depsPtr + qu;
|
||||||
|
clShowPrefix = qu + showPtr + qu;
|
||||||
vars.DependencyFile = "$DEP_FILE";
|
vars.DependencyFile = "$DEP_FILE";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -392,8 +393,10 @@ cmNinjaTargetGenerator
|
||||||
|
|
||||||
if(useClDeps)
|
if(useClDeps)
|
||||||
{
|
{
|
||||||
cmdLine = "\"" + clDepsBinary + "\" $in \"$DEP_FILE\" $out \""
|
std::string cl = mf->GetDefinition("CMAKE_C_COMPILER");
|
||||||
+ clShowPrefix + "\" " + cmdLine;
|
cl = "\"" + cl + "\" ";
|
||||||
|
cmdLine = clDepsBinary + " " + lang + " $in \"$DEP_FILE\" $out "
|
||||||
|
+ clShowPrefix + " " + cl + cmdLine;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write the rule for compiling file of the given language.
|
// Write the rule for compiling file of the given language.
|
||||||
|
|
|
@ -535,14 +535,17 @@ static string getArg(string& cmdline) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void parseCommandLine(LPTSTR wincmdline,
|
static void parseCommandLine(LPTSTR wincmdline,
|
||||||
|
string& lang,
|
||||||
string& srcfile,
|
string& srcfile,
|
||||||
string& dfile,
|
string& dfile,
|
||||||
string& objfile,
|
string& objfile,
|
||||||
string& prefix,
|
string& prefix,
|
||||||
string& clpath,
|
string& clpath,
|
||||||
|
string& binpath,
|
||||||
string& rest) {
|
string& rest) {
|
||||||
string cmdline(wincmdline);
|
string cmdline(wincmdline);
|
||||||
/* self */ getArg(cmdline);
|
/* self */ getArg(cmdline);
|
||||||
|
lang = getArg(cmdline);
|
||||||
srcfile = getArg(cmdline);
|
srcfile = getArg(cmdline);
|
||||||
std::string::size_type pos = srcfile.rfind("\\");
|
std::string::size_type pos = srcfile.rfind("\\");
|
||||||
if (pos != string::npos) {
|
if (pos != string::npos) {
|
||||||
|
@ -554,12 +557,16 @@ static void parseCommandLine(LPTSTR wincmdline,
|
||||||
objfile = getArg(cmdline);
|
objfile = getArg(cmdline);
|
||||||
prefix = getArg(cmdline);
|
prefix = getArg(cmdline);
|
||||||
clpath = getArg(cmdline);
|
clpath = getArg(cmdline);
|
||||||
|
binpath = getArg(cmdline);
|
||||||
rest = trimLeadingSpace(cmdline);
|
rest = trimLeadingSpace(cmdline);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void outputDepFile(const string& dfile, const string& objfile,
|
static void outputDepFile(const string& dfile, const string& objfile,
|
||||||
vector<string>& incs) {
|
vector<string>& incs) {
|
||||||
|
|
||||||
|
if (dfile.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
// strip duplicates
|
// strip duplicates
|
||||||
sort(incs.begin(), incs.end());
|
sort(incs.begin(), incs.end());
|
||||||
incs.erase(unique(incs.begin(), incs.end()), incs.end());
|
incs.erase(unique(incs.begin(), incs.end()), incs.end());
|
||||||
|
@ -581,6 +588,7 @@ static void outputDepFile(const string& dfile, const string& objfile,
|
||||||
//doEscape(tmp, "(", "\\("); // TODO ninja can't read ( and )
|
//doEscape(tmp, "(", "\\("); // TODO ninja can't read ( and )
|
||||||
//doEscape(tmp, ")", "\\)");
|
//doEscape(tmp, ")", "\\)");
|
||||||
fprintf(out, "%s \\\n", tmp.c_str());
|
fprintf(out, "%s \\\n", tmp.c_str());
|
||||||
|
//printf("include: %s \n", tmp.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(out, "\n");
|
fprintf(out, "\n");
|
||||||
|
@ -596,29 +604,26 @@ bool contains(const std::string& str, const std::string& what) {
|
||||||
return str.find(what) != std::string::npos;
|
return str.find(what) != std::string::npos;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
std::string replace(const std::string& str, const std::string& what, const std::string& replacement) {
|
||||||
|
size_t pos = str.find(what);
|
||||||
|
if (pos == std::string::npos)
|
||||||
|
return str;
|
||||||
|
std::string replaced = str;
|
||||||
|
return replaced.replace(pos, what.size(), replacement);
|
||||||
|
}
|
||||||
|
|
||||||
// Use the Win32 api instead of argc/argv so we can avoid interpreting the
|
|
||||||
// rest of command line after the .d and .obj. Custom parsing seemed
|
|
||||||
// preferable to the ugliness you get into in trying to re-escape quotes for
|
|
||||||
// subprocesses, so by avoiding argc/argv, the subprocess is called with
|
|
||||||
// the same command line verbatim.
|
|
||||||
|
|
||||||
string srcfile, dfile, objfile, prefix, clpath, rest;
|
|
||||||
parseCommandLine(GetCommandLine(), srcfile, dfile, objfile,
|
|
||||||
prefix, clpath, rest);
|
|
||||||
|
|
||||||
#if 0
|
static int process(bool ignoreErrors,
|
||||||
fprintf(stderr, "\n\ncmcldebug:\n");
|
const string& srcfile,
|
||||||
fprintf(stderr, ".d : %s\n", dfile.c_str());
|
const string& dfile,
|
||||||
fprintf(stderr, "OBJ : %s\n", objfile.c_str());
|
const string& objfile,
|
||||||
fprintf(stderr, "CL : %s\n", clpath.c_str());
|
const string& prefix,
|
||||||
fprintf(stderr, "REST: %s\n", rest.c_str());
|
const string& cmd) {
|
||||||
fprintf(stderr, "\n\n");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
SubprocessSet subprocs;
|
SubprocessSet subprocs;
|
||||||
Subprocess* subproc = subprocs.Add(clpath + " /showIncludes " + rest);
|
Subprocess* subproc = subprocs.Add(cmd);
|
||||||
|
|
||||||
if(!subproc)
|
if(!subproc)
|
||||||
return 2;
|
return 2;
|
||||||
|
|
||||||
|
@ -647,18 +652,67 @@ int main() {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!isFirstLine || !startsWith(line, srcfile)) {
|
if (!isFirstLine || !startsWith(line, srcfile)) {
|
||||||
|
if (!ignoreErrors) {
|
||||||
|
// suppress errors when cl is fed with a rc file
|
||||||
fprintf(stdout, "%s\n", line.c_str());
|
fprintf(stdout, "%s\n", line.c_str());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
isFirstLine = false;
|
isFirstLine = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!success)
|
if (!success) {
|
||||||
|
if (ignoreErrors) {
|
||||||
|
//printf("\n-- RC file %i dependencies in %s\n\n", includes.size(), dfile.c_str());
|
||||||
|
outputDepFile(dfile, objfile, includes);
|
||||||
|
}
|
||||||
return exit_code;
|
return exit_code;
|
||||||
|
}
|
||||||
|
|
||||||
// don't update .d until/unless we succeed compilation
|
// don't update .d until/unless we succeed compilation
|
||||||
outputDepFile(dfile, objfile, includes);
|
outputDepFile(dfile, objfile, includes);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
|
||||||
|
// Use the Win32 api instead of argc/argv so we can avoid interpreting the
|
||||||
|
// rest of command line after the .d and .obj. Custom parsing seemed
|
||||||
|
// preferable to the ugliness you get into in trying to re-escape quotes for
|
||||||
|
// subprocesses, so by avoiding argc/argv, the subprocess is called with
|
||||||
|
// the same command line verbatim.
|
||||||
|
|
||||||
|
string lang, srcfile, dfile, objfile, prefix, cl, binpath, rest;
|
||||||
|
parseCommandLine(GetCommandLine(), lang, srcfile, dfile, objfile,
|
||||||
|
prefix, cl, binpath, rest);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
fprintf(stderr, "\n\ncmcldebug:\n");
|
||||||
|
fprintf(stderr, ".d : %s\n", dfile.c_str());
|
||||||
|
fprintf(stderr, "OBJ : %s\n", objfile.c_str());
|
||||||
|
fprintf(stderr, "CL : %s\n", clpath.c_str());
|
||||||
|
fprintf(stderr, "REST: %s\n", rest.c_str());
|
||||||
|
fprintf(stderr, "\n\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (lang != "RC") {
|
||||||
|
return process(false, srcfile, dfile, objfile, prefix, binpath + " /showIncludes " + rest);
|
||||||
|
} else {
|
||||||
|
// "misuse" cl.exe to get headers from .rc files
|
||||||
|
// rc: /fo x\CMakeFiles\x.dir\x.rc.res src\x\x.rc
|
||||||
|
// cl: /out:x\CMakeFiles\x.dir\x.rc.res.dep.obj /Tc src\x\x.rc
|
||||||
|
|
||||||
|
cl = "\"" + cl + "\" /showIncludes ";
|
||||||
|
string clRest = rest;
|
||||||
|
clRest = replace(clRest, "/fo" + objfile, "/out:" + objfile + ".dep.obj /Tc ");
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
ret = process(true, srcfile, dfile, objfile, prefix, cl + clRest);
|
||||||
|
ret = process(false, srcfile, "" , objfile, prefix, binpath + " " + rest);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue