/** * Program to copy and patch MSVC header files to work with GCC-XML. */ #include "gxSystemTools.h" #include #include #include #include #include #include #include #include #include bool InstallSupport(const char* patchCommand, const char* catCommand, const char* patchFile, const char* sourcePath, const char* destPath); bool FindTool(const char* vcDir, const char* name, std::string& result); //---------------------------------------------------------------------------- int main(int argc, char* argv[]) { if(argc < 2) { std::cout << "Usage:" << std::endl << " " << argv[0] << " patch_dir [gccxml_root] [timestamp_file]" << std::endl; return 0; } std::string patchDir = argv[1]; std::string gccxmlRoot = "."; std::string timestamp; if(argc >= 3) { gccxmlRoot = argv[2]; // Make sure the output directory exists. gxSystemTools::MakeDirectory(gccxmlRoot.c_str()); } if(argc >= 4) { timestamp = argv[3]; } // Clean up the paths. patchDir = gxSystemTools::CollapseDirectory(patchDir.c_str()); gccxmlRoot = gxSystemTools::CollapseDirectory(gccxmlRoot.c_str()); gxSystemTools::ConvertToUnixSlashes(patchDir); gxSystemTools::ConvertToUnixSlashes(gccxmlRoot); // Wipe out any existing VC support directories. We will create // them from scratch. gxSystemTools::RemoveADirectory((gccxmlRoot+"/Vc6").c_str()); gxSystemTools::RemoveADirectory((gccxmlRoot+"/Vc7").c_str()); gxSystemTools::RemoveADirectory((gccxmlRoot+"/Vc71").c_str()); gxSystemTools::RemoveADirectory((gccxmlRoot+"/Vc8").c_str()); gxSystemTools::RemoveADirectory((gccxmlRoot+"/Vc8ex").c_str()); gxSystemTools::RemoveADirectory((gccxmlRoot+"/Vc9").c_str()); gxSystemTools::RemoveADirectory((gccxmlRoot+"/Vc10").c_str()); // The registry keys for MSVC install detection. const char* vc6Registry = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\" "DevStudio\\6.0\\Products\\Microsoft Visual C++;ProductDir"; const char* vc7Registry = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\7.0\\Setup\\VC;ProductDir"; const char* vc71Registry = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\7.1\\Setup\\VC;ProductDir"; const char* vc8Registry = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\8.0\\Setup\\VC;ProductDir"; const char* vc8sp1Registry[] = { // English SP1 "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\8.0\\InstalledProducts\\KB926601;", // German SP1 "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\8.0\\InstalledProducts\\KB926606;", 0 }; const char* vc8exRegistry = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\8.0\\Setup\\VC;ProductDir"; const char* vc8exSP1Registry = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\8.0\\InstalledProducts\\KB926748;"; const char* vc8sdkRegistry = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\MicrosoftSDK\\InstalledSDKs\\8F9E5EF3-A9A5-491B-A889-C58EFFECE8B3;Install Dir"; const char* vc8sdk2Registry = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\MicrosoftSDK\\InstalledSDKs\\D2FF9F89-8AA2-4373-8A31-C838BF4DBBE1;Install Dir"; const char* vc9Registry = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\9.0\\Setup\\VC;ProductDir"; const char* vc9sp1Registry[] = { // English SP1 "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\9.0\\InstalledProducts\\KB948484;", // Team System English SP1 "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\9.0\\InstalledProducts\\KB947888;", 0 }; const char* vc9exRegistry = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\9.0\\Setup\\VC;ProductDir"; const char* vc9sdkRegistry = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\v6.0A;InstallationFolder"; const char* vc10Registry = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\10.0\\Setup\\VC;ProductDir"; const char* vc10sdkRegistry = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\v7.0A;InstallationFolder"; // Check which versions of MSVC are installed. std::string msvc6; std::string msvc7; std::string msvc71; std::string msvc8; std::string msvc8ex; std::string msvc8sdk; std::string msvc9; std::string msvc9sdk; std::string msvc10; std::string msvc10sdk; bool have6 = gxSystemTools::ReadRegistryValue(vc6Registry, msvc6); bool have7 = gxSystemTools::ReadRegistryValue(vc7Registry, msvc7); bool have71 = gxSystemTools::ReadRegistryValue(vc71Registry, msvc71); bool have8 = false; bool have8ex = false; bool have9 = (gxSystemTools::ReadRegistryValue(vc9Registry, msvc9) || gxSystemTools::ReadRegistryValue(vc9exRegistry, msvc9)); bool have9sdk = have9 && gxSystemTools::ReadRegistryValue(vc9sdkRegistry, msvc9sdk); bool have10 = gxSystemTools::ReadRegistryValue(vc10Registry, msvc10); bool have10sdk = have10 && gxSystemTools::ReadRegistryValue(vc10sdkRegistry, msvc10sdk); // Look for a VS8 express that is not the beta release. if(gxSystemTools::ReadRegistryValue(vc8exRegistry, msvc8ex)) { // The "CLR Version" registry entry in VS 8 has value "v2.0.40607" // for the beta and "v2.0.50727" for the release. const char* vc8RegistryVersion = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\8.0;CLR Version"; std::string version; if(gxSystemTools::ReadRegistryValue(vc8RegistryVersion, version)) { int vnum; if((sscanf(version.c_str(), "v2.0.%d", &vnum) == 1) && vnum >= 50727) { have8ex = true; } } } bool have8sdk = have8ex && (gxSystemTools::ReadRegistryValue(vc8sdk2Registry, msvc8sdk) || gxSystemTools::ReadRegistryValue(vc8sdkRegistry, msvc8sdk)); // Look for a VS8 that is not the beta release. if(gxSystemTools::ReadRegistryValue(vc8Registry, msvc8)) { // The "CLR Version" registry entry in VS 8 has value "v2.0.40607" // for the beta and "v2.0.50727" for the release. const char* vc8RegistryVersion = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\8.0;CLR Version"; std::string version; if(gxSystemTools::ReadRegistryValue(vc8RegistryVersion, version)) { int vnum; if((sscanf(version.c_str(), "v2.0.%d", &vnum) == 1) && vnum >= 50727) { have8 = true; } } } // See if there is anything to do. if(!have6 && !have7 && !have71 && !have8 && !have8ex && !have9 && !have10) { std::cout << "None of MSVC 6, 7, 7.1, 8, 9 or 10 is installed.\n"; } // Need to install at least one of the support directories. We need // to find the cat and patch executables. std::string patchCommand; if(!FindTool(patchDir.c_str(), "patch", patchCommand) && (have6||have7||have71||have8||have8ex||have9||have10)) { std::cerr << "Cannot find patch executable.\n"; return 1; } std::string catCommand; if(!FindTool(patchDir.c_str(), "cat", catCommand) && (have6||have7||have71||have8||have8ex||have9||have10)) { std::cerr << "Cannot find cat executable.\n"; return 1; } int result = 0; if(have6) { msvc6 += "/Include"; std::string patchFile = patchDir + "/vc6Include.patch"; std::string destPath = gccxmlRoot+"/Vc6/Include"; if(gxSystemTools::FileExists(patchFile.c_str())) { if(!InstallSupport(patchCommand.c_str(), catCommand.c_str(), patchFile.c_str(), msvc6.c_str(), destPath.c_str())) { result = 1; } } else { std::cerr << "Have MSVC 6, but cannot find vc6Include.patch.\n"; result = 1; } } if(have7) { std::string msvc7i = msvc7 + "/Include"; std::string msvc7p = msvc7 + "/PlatformSDK/Include"; msvc7i = gxSystemTools::CollapseDirectory(msvc7i.c_str()); msvc7p = gxSystemTools::CollapseDirectory(msvc7p.c_str()); std::string patchI = patchDir + "/vc7Include.patch"; std::string patchP = patchDir + "/vc7PlatformSDK.patch"; std::string destPathI = gccxmlRoot+"/Vc7/Include"; std::string destPathP = gccxmlRoot+"/Vc7/PlatformSDK"; if(gxSystemTools::FileExists(patchI.c_str())) { if(!InstallSupport(patchCommand.c_str(), catCommand.c_str(), patchI.c_str(), msvc7i.c_str(), destPathI.c_str())) { result = 1; } } else { std::cerr << "Have MSVC 7, but cannot find vc7Include.patch.\n"; result = 1; } if(gxSystemTools::FileExists(patchP.c_str())) { if(!InstallSupport(patchCommand.c_str(), catCommand.c_str(), patchP.c_str(), msvc7p.c_str(), destPathP.c_str())) { result = 1; } } else { std::cerr << "Have MSVC 7, but cannot find vc7PlatformSDK.patch.\n"; result = 1; } } if(have71) { std::string msvc71i = msvc71 + "/Include"; std::string msvc71p = msvc71 + "/PlatformSDK/Include"; msvc71i = gxSystemTools::CollapseDirectory(msvc71i.c_str()); msvc71p = gxSystemTools::CollapseDirectory(msvc71p.c_str()); std::string patchI = patchDir + "/vc71Include.patch"; std::string patchP = patchDir + "/vc71PlatformSDK.patch"; std::string destPathI = gccxmlRoot+"/Vc71/Include"; std::string destPathP = gccxmlRoot+"/Vc71/PlatformSDK"; if(gxSystemTools::FileExists(patchI.c_str())) { if(!InstallSupport(patchCommand.c_str(), catCommand.c_str(), patchI.c_str(), msvc71i.c_str(), destPathI.c_str())) { result = 1; } } else { std::cerr << "Have MSVC 7.1, but cannot find vc71Include.patch.\n"; result = 1; } if(gxSystemTools::FileExists(patchP.c_str())) { if(!InstallSupport(patchCommand.c_str(), catCommand.c_str(), patchP.c_str(), msvc71p.c_str(), destPathP.c_str())) { result = 1; } } else { std::cerr << "Have MSVC 7.1, but cannot find vc71PlatformSDK.patch.\n"; result = 1; } } if(have8) { std::string msvc8i = msvc8 + "/Include"; std::string msvc8p = msvc8 + "/PlatformSDK/Include"; msvc8i = gxSystemTools::CollapseDirectory(msvc8i.c_str()); msvc8p = gxSystemTools::CollapseDirectory(msvc8p.c_str()); std::string patchIname = "vc8Include.patch"; std::string patchPname = "vc8PlatformSDK.patch"; std::string destPathI = gccxmlRoot+"/Vc8/Include"; std::string destPathP = gccxmlRoot+"/Vc8/PlatformSDK"; std::string msvc8sp1; bool vc8sp1 = false; for(const char** reg = vc8sp1Registry; !vc8sp1 && *reg; ++reg) { vc8sp1 = vc8sp1 || gxSystemTools::ReadRegistryValue(*reg, msvc8sp1); } if(vc8sp1) { patchIname = "vc8sp1Include.patch"; patchPname = "vc8sp1PlatformSDK.patch"; } std::string patchI = patchDir + "/" + patchIname; std::string patchP = patchDir + "/" + patchPname; if(gxSystemTools::FileExists(patchI.c_str())) { if(!InstallSupport(patchCommand.c_str(), catCommand.c_str(), patchI.c_str(), msvc8i.c_str(), destPathI.c_str())) { result = 1; } } else { std::cerr << "Have MSVC 8, but cannot find " << patchIname << ".\n"; result = 1; } if(gxSystemTools::FileExists(patchP.c_str())) { if(!InstallSupport(patchCommand.c_str(), catCommand.c_str(), patchP.c_str(), msvc8p.c_str(), destPathP.c_str())) { result = 1; } } else { std::cerr << "Have MSVC 8, but cannot find " << patchPname << ".\n"; result = 1; } } if(have8ex) { std::string msvc8i = msvc8ex + "/Include"; msvc8i = gxSystemTools::CollapseDirectory(msvc8i.c_str()); std::string patchIname = "vc8ExpressInclude.patch"; std::string destPathI = gccxmlRoot+"/Vc8ex/Include"; std::string msvc8exSP1; if(gxSystemTools::ReadRegistryValue(vc8exSP1Registry, msvc8exSP1)) { patchIname = "vc8sp1ExpressInclude.patch"; } std::string patchI = patchDir + "/" + patchIname; if(gxSystemTools::FileExists(patchI.c_str())) { if(!InstallSupport(patchCommand.c_str(), catCommand.c_str(), patchI.c_str(), msvc8i.c_str(), destPathI.c_str())) { result = 1; } } else { std::cerr << "Have MSVC 8 Express, but cannot find " << patchIname << ".\n"; result = 1; } } if(have8sdk) { std::string msvc8p = msvc8sdk + "/Include"; msvc8p = gxSystemTools::CollapseDirectory(msvc8p.c_str()); std::string patchPname = "vc8ExpressPlatformSDK.patch"; std::string destPathP = gccxmlRoot+"/Vc8ex/PlatformSDK"; std::string patchP = patchDir + "/" + patchPname; if(gxSystemTools::FileExists(patchP.c_str())) { if(!InstallSupport(patchCommand.c_str(), catCommand.c_str(), patchP.c_str(), msvc8p.c_str(), destPathP.c_str())) { result = 1; } } else { std::cerr << "Have MSVC 8 Express Platform SDK, but " << "cannot find " << patchPname << ".\n"; result = 1; } } if(have9) { std::string msvc9i = msvc9 + "/Include"; msvc9i = gxSystemTools::CollapseDirectory(msvc9i.c_str()); std::string patchIname = "vc9Include.patch"; std::string destPathI = gccxmlRoot+"/Vc9/Include"; std::string msvc9sp1; bool vc9sp1 = false; for(const char** reg = vc9sp1Registry; !vc9sp1 && *reg; ++reg) { vc9sp1 = vc9sp1 || gxSystemTools::ReadRegistryValue(*reg, msvc9sp1); } if(vc9sp1) { patchIname = "vc9sp1Include.patch"; } std::string patchI = patchDir + "/" + patchIname; if(gxSystemTools::FileExists(patchI.c_str())) { if(!InstallSupport(patchCommand.c_str(), catCommand.c_str(), patchI.c_str(), msvc9i.c_str(), destPathI.c_str())) { result = 1; } } else { std::cerr << "Have MSVC 9, but cannot find " << patchIname << ".\n"; result = 1; } } if(have9sdk) { std::string msvc9p = msvc9sdk + "/Include"; msvc9p = gxSystemTools::CollapseDirectory(msvc9p.c_str()); std::string patchPname = "vc9PlatformSDK.patch"; std::string destPathP = gccxmlRoot+"/Vc9/PlatformSDK"; std::string patchP = patchDir + "/" + patchPname; if(gxSystemTools::FileExists(patchP.c_str())) { if(!InstallSupport(patchCommand.c_str(), catCommand.c_str(), patchP.c_str(), msvc9p.c_str(), destPathP.c_str())) { result = 1; } } else { std::cerr << "Have MSVC 9 Platform SDK, but " << "cannot find " << patchPname << ".\n"; result = 1; } } if(have10) { std::string msvc10i = msvc10 + "/Include"; msvc10i = gxSystemTools::CollapseDirectory(msvc10i.c_str()); std::string patchIname = "vc10Include.patch"; std::string destPathI = gccxmlRoot+"/Vc10/Include"; std::string msvc10sp1; std::string patchI = patchDir + "/" + patchIname; if(gxSystemTools::FileExists(patchI.c_str())) { if(!InstallSupport(patchCommand.c_str(), catCommand.c_str(), patchI.c_str(), msvc10i.c_str(), destPathI.c_str())) { result = 1; } } else { std::cerr << "Have MSVC 10, but cannot find " << patchIname << ".\n"; result = 1; } } if(have10sdk) { std::string msvc10p = msvc10sdk + "/Include"; msvc10p = gxSystemTools::CollapseDirectory(msvc10p.c_str()); std::string patchPname = "vc10PlatformSDK.patch"; std::string destPathP = gccxmlRoot+"/Vc10/PlatformSDK"; std::string patchP = patchDir + "/" + patchPname; if(gxSystemTools::FileExists(patchP.c_str())) { if(!InstallSupport(patchCommand.c_str(), catCommand.c_str(), patchP.c_str(), msvc10p.c_str(), destPathP.c_str())) { result = 1; } } else { std::cerr << "Have MSVC 10 Platform SDK, but " << "cannot find " << patchPname << ".\n"; result = 1; } } // If we succeeded, write the timestamp file. if(result == 0 && (timestamp.length() > 0)) { std::ofstream tfile(timestamp.c_str(), std::ios::out | std::ios::binary); tfile << "int main() { return 0; }\n"; if(!tfile) { std::cerr << "Error writing timestamp file \"" << timestamp.c_str() << "\".\n"; result = 1; } } return result; } //---------------------------------------------------------------------------- bool InstallSupport(const char* patchCommand, const char* catCommand, const char* patchFile, const char* sourcePath, const char* destPath) { // Look at the patch file to see what headers need to be copied. std::ifstream patch(patchFile); if(!patch) { std::cerr << "Error opening patch file " << patchFile << std::endl; return false; } // Make sure the destination path exists. gxSystemTools::MakeDirectory(destPath); // Copy the files over before patching. char buf[4096]; for(patch.getline(buf, 4096); !patch.eof(); patch.getline(buf, 4096)) { std::string line = buf; if(line.substr(0,6) == "Index:") { std::string source = sourcePath; source += "/"+line.substr(7); std::string dest = destPath; dest += "/"+line.substr(7); gxSystemTools::FileCopy(source.c_str(), dest.c_str()); mode_t mode; if(gxSystemTools::GetPermissions(dest.c_str(), mode)) { mode = mode | 0200; gxSystemTools::SetPermissions(dest.c_str(), mode); } } } std::string cmd = catCommand; if(cmd.find(" ") != cmd.npos) { if(gxSystemTools::GetShortPath(catCommand, cmd)) { catCommand = cmd.c_str(); } } std::string patchCmd = gxSystemTools::ConvertToOutputPath(catCommand); patchCmd += " "; patchCmd += gxSystemTools::ConvertToOutputPath(patchFile); patchCmd += " | "; patchCmd += gxSystemTools::ConvertToOutputPath(patchCommand); patchCmd += " -p0 -t -d "; patchCmd += gxSystemTools::ConvertToOutputPath(destPath); // Patch the copies of the header files. std::cout << "Executing " << patchCmd.c_str() << std::endl; std::string output; int retVal; if(gxSystemTools::RunCommand(patchCmd.c_str(), output, retVal) && (retVal == 0)) { return true; } std::cerr << "Error running patch. Output is [" << output.c_str() << "]\n"; return false; } //---------------------------------------------------------------------------- bool FindTool(const char* vcDir, const char* name, std::string& result) { // check for executable in the source directory std::string command = vcDir; command += "/vc"; command += name; command += ".exe"; if(gxSystemTools::FileExists(command.c_str())) { result = command; return true; } // Find the executable. command = name; command += ".exe"; if(gxSystemTools::FileExists(command.c_str())) { result = command; return true; } else { // The registry key to use to find the executable from cygwin. const char* cygwinRegistry1 = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Cygnus Solutions\\Cygwin\\mounts v2\\/usr/bin;native"; const char* cygwinRegistry2 = "HKEY_CURRENT_USER\\Software\\Cygnus Solutions\\Cygwin\\mounts v2\\/usr/bin;native"; if((gxSystemTools::ReadRegistryValue(cygwinRegistry1, command) || gxSystemTools::ReadRegistryValue(cygwinRegistry2, command)) && gxSystemTools::FileExists((command+"/"+name+".exe").c_str())) { // Found the binary location from cygwin's registry entry. command += "/"; command += name; command += ".exe"; result = command; return true; } else { // Try to find it in the path. command = gxSystemTools::FindProgram(name); if(command.length() > 0) { result = command; return true; } } } return false; }