mirror of
https://github.com/Kitware/CMake.git
synced 2025-10-21 06:10:16 +08:00
Windows: Improve link-time error messages when rc or mt fail
We run extra tools during linking on Windows to deal with manifests. Report more information when these tools fail. For example, if the Windows SDK is not installed with VS then `rc.exe` will be missing.
This commit is contained in:

committed by
Brad King

parent
c2d6835c17
commit
0a8e23ad6e
@@ -1537,8 +1537,34 @@ int cmcmd::VisualStudioLink(std::vector<std::string> const& args, int type)
|
|||||||
return vsLink.Link();
|
return vsLink.Link();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum NumberFormat
|
||||||
|
{
|
||||||
|
FORMAT_DECIMAL,
|
||||||
|
FORMAT_HEX
|
||||||
|
};
|
||||||
|
struct NumberFormatter
|
||||||
|
{
|
||||||
|
NumberFormat Format;
|
||||||
|
int Value;
|
||||||
|
NumberFormatter(NumberFormat format, int value)
|
||||||
|
: Format(format)
|
||||||
|
, Value(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
std::ostream& operator<<(std::ostream& stream,
|
||||||
|
NumberFormatter const& formatter)
|
||||||
|
{
|
||||||
|
if (formatter.Format == FORMAT_DECIMAL) {
|
||||||
|
stream << formatter.Value;
|
||||||
|
} else {
|
||||||
|
stream << "0x" << std::hex << formatter.Value;
|
||||||
|
}
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
static bool RunCommand(const char* comment, std::vector<std::string>& command,
|
static bool RunCommand(const char* comment, std::vector<std::string>& command,
|
||||||
bool verbose, int* retCodeOut = nullptr)
|
bool verbose, NumberFormat exitFormat,
|
||||||
|
int* retCodeOut = nullptr)
|
||||||
{
|
{
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
std::cout << comment << ":\n";
|
std::cout << comment << ":\n";
|
||||||
@@ -1546,31 +1572,33 @@ static bool RunCommand(const char* comment, std::vector<std::string>& command,
|
|||||||
}
|
}
|
||||||
std::string output;
|
std::string output;
|
||||||
int retCode = 0;
|
int retCode = 0;
|
||||||
// use rc command to create .res file
|
bool commandResult = cmSystemTools::RunSingleCommand(
|
||||||
bool res = cmSystemTools::RunSingleCommand(
|
|
||||||
command, &output, &output, &retCode, nullptr, cmSystemTools::OUTPUT_NONE);
|
command, &output, &output, &retCode, nullptr, cmSystemTools::OUTPUT_NONE);
|
||||||
|
bool returnValue;
|
||||||
|
if (retCodeOut) {
|
||||||
|
if (!commandResult) {
|
||||||
|
*retCodeOut = (retCode == 0) ? -1 : retCode;
|
||||||
|
} else {
|
||||||
|
*retCodeOut = retCode;
|
||||||
|
}
|
||||||
|
returnValue = true; // always return true if retCodeOut is requested
|
||||||
|
} else {
|
||||||
|
returnValue = commandResult && (retCode == 0);
|
||||||
|
}
|
||||||
|
if (!commandResult || retCode) {
|
||||||
|
std::cout << comment << ": command \"" << cmJoin(command, " ")
|
||||||
|
<< "\" failed (exit code "
|
||||||
|
<< NumberFormatter(exitFormat, retCode)
|
||||||
|
<< ") with the following output:\n"
|
||||||
|
<< output;
|
||||||
|
} else {
|
||||||
// always print the output of the command, unless
|
// always print the output of the command, unless
|
||||||
// it is the dumb rc command banner, but if the command
|
// it is the dumb rc command banner
|
||||||
// returned an error code then print the output anyway as
|
if (output.find("Resource Compiler Version") == std::string::npos) {
|
||||||
// the banner may be mixed with some other important information.
|
|
||||||
if (output.find("Resource Compiler Version") == std::string::npos || !res ||
|
|
||||||
retCode) {
|
|
||||||
std::cout << output;
|
std::cout << output;
|
||||||
}
|
}
|
||||||
if (!res) {
|
|
||||||
std::cout << comment << " failed to run." << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
// if retCodeOut is requested then always return true
|
return returnValue;
|
||||||
// and set the retCodeOut to retCode
|
|
||||||
if (retCodeOut) {
|
|
||||||
*retCodeOut = retCode;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (retCode != 0) {
|
|
||||||
std::cout << comment << " failed. with " << retCode << "\n";
|
|
||||||
}
|
|
||||||
return retCode == 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cmVSLink::Parse(std::vector<std::string>::const_iterator argBeg,
|
bool cmVSLink::Parse(std::vector<std::string>::const_iterator argBeg,
|
||||||
@@ -1720,10 +1748,10 @@ int cmVSLink::LinkIncremental()
|
|||||||
|
|
||||||
// Compile the resource file.
|
// Compile the resource file.
|
||||||
std::vector<std::string> rcCommand;
|
std::vector<std::string> rcCommand;
|
||||||
rcCommand.push_back(cmSystemTools::FindProgram("rc.exe"));
|
rcCommand.push_back("rc");
|
||||||
rcCommand.push_back("/fo" + this->ManifestFileRes);
|
rcCommand.push_back("/fo" + this->ManifestFileRes);
|
||||||
rcCommand.push_back(this->ManifestFileRC);
|
rcCommand.push_back(this->ManifestFileRC);
|
||||||
if (!RunCommand("RC Pass 1", rcCommand, this->Verbose)) {
|
if (!RunCommand("RC Pass 1", rcCommand, this->Verbose, FORMAT_DECIMAL)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1731,7 +1759,8 @@ int cmVSLink::LinkIncremental()
|
|||||||
this->LinkCommand.push_back(this->ManifestFileRes);
|
this->LinkCommand.push_back(this->ManifestFileRes);
|
||||||
|
|
||||||
// Run the link command (possibly generates intermediate manifest).
|
// Run the link command (possibly generates intermediate manifest).
|
||||||
if (!RunCommand("LINK Pass 1", this->LinkCommand, this->Verbose)) {
|
if (!RunCommand("LINK Pass 1", this->LinkCommand, this->Verbose,
|
||||||
|
FORMAT_DECIMAL)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1745,12 +1774,13 @@ int cmVSLink::LinkIncremental()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Compile the resource file again.
|
// Compile the resource file again.
|
||||||
if (!RunCommand("RC Pass 2", rcCommand, this->Verbose)) {
|
if (!RunCommand("RC Pass 2", rcCommand, this->Verbose, FORMAT_DECIMAL)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Link incrementally again to use the updated resource.
|
// Link incrementally again to use the updated resource.
|
||||||
if (!RunCommand("FINAL LINK", this->LinkCommand, this->Verbose)) {
|
if (!RunCommand("FINAL LINK", this->LinkCommand, this->Verbose,
|
||||||
|
FORMAT_DECIMAL)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1759,7 +1789,7 @@ int cmVSLink::LinkIncremental()
|
|||||||
int cmVSLink::LinkNonIncremental()
|
int cmVSLink::LinkNonIncremental()
|
||||||
{
|
{
|
||||||
// Run the link command (possibly generates intermediate manifest).
|
// Run the link command (possibly generates intermediate manifest).
|
||||||
if (!RunCommand("LINK", this->LinkCommand, this->Verbose)) {
|
if (!RunCommand("LINK", this->LinkCommand, this->Verbose, FORMAT_DECIMAL)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1777,7 +1807,7 @@ int cmVSLink::LinkNonIncremental()
|
|||||||
int cmVSLink::RunMT(std::string const& out, bool notify)
|
int cmVSLink::RunMT(std::string const& out, bool notify)
|
||||||
{
|
{
|
||||||
std::vector<std::string> mtCommand;
|
std::vector<std::string> mtCommand;
|
||||||
mtCommand.push_back(cmSystemTools::FindProgram("mt.exe"));
|
mtCommand.push_back("mt");
|
||||||
mtCommand.push_back("/nologo");
|
mtCommand.push_back("/nologo");
|
||||||
mtCommand.push_back("/manifest");
|
mtCommand.push_back("/manifest");
|
||||||
if (this->LinkGeneratesManifest) {
|
if (this->LinkGeneratesManifest) {
|
||||||
@@ -1792,7 +1822,7 @@ int cmVSLink::RunMT(std::string const& out, bool notify)
|
|||||||
mtCommand.push_back("/notify_update");
|
mtCommand.push_back("/notify_update");
|
||||||
}
|
}
|
||||||
int mtRet = 0;
|
int mtRet = 0;
|
||||||
if (!RunCommand("MT", mtCommand, this->Verbose, &mtRet)) {
|
if (!RunCommand("MT", mtCommand, this->Verbose, FORMAT_HEX, &mtRet)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return mtRet;
|
return mtRet;
|
||||||
|
Reference in New Issue
Block a user