cmCPackNSISGenerator.cxx 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. /*=========================================================================
  2. Program: CMake - Cross-Platform Makefile Generator
  3. Module: $RCSfile$
  4. Language: C++
  5. Date: $Date$
  6. Version: $Revision$
  7. Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
  8. See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
  9. This software is distributed WITHOUT ANY WARRANTY; without even
  10. the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  11. PURPOSE. See the above copyright notices for more information.
  12. =========================================================================*/
  13. #include "cmCPackNSISGenerator.h"
  14. #include "cmGlobalGenerator.h"
  15. #include "cmLocalGenerator.h"
  16. #include "cmSystemTools.h"
  17. #include "cmMakefile.h"
  18. #include "cmGeneratedFileStream.h"
  19. #include "cmCPackLog.h"
  20. #include <cmsys/SystemTools.hxx>
  21. #include <cmsys/Glob.hxx>
  22. #include <cmsys/Directory.hxx>
  23. #include <cmsys/RegularExpression.hxx>
  24. //----------------------------------------------------------------------
  25. cmCPackNSISGenerator::cmCPackNSISGenerator()
  26. {
  27. }
  28. //----------------------------------------------------------------------
  29. cmCPackNSISGenerator::~cmCPackNSISGenerator()
  30. {
  31. }
  32. //----------------------------------------------------------------------
  33. int cmCPackNSISGenerator::CompressFiles(const char* outFileName,
  34. const char* toplevel, const std::vector<std::string>& files)
  35. {
  36. (void)outFileName; // TODO: Fix nsis to force out file name
  37. (void)toplevel;
  38. std::string nsisInFileName = this->FindTemplate("NSIS.template.in");
  39. if ( nsisInFileName.size() == 0 )
  40. {
  41. cmCPackLogger(cmCPackLog::LOG_ERROR,
  42. "CPack error: Could not find NSIS installer template file."
  43. << std::endl);
  44. return false;
  45. }
  46. std::string nsisFileName = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
  47. std::string tmpFile = nsisFileName;
  48. tmpFile += "/NSISOutput.log";
  49. nsisFileName += "/project.nsi";
  50. cmOStringStream str;
  51. std::vector<std::string>::const_iterator it;
  52. for ( it = files.begin(); it != files.end(); ++ it )
  53. {
  54. std::string fileN = cmSystemTools::RelativePath(toplevel,
  55. it->c_str());
  56. cmSystemTools::ReplaceString(fileN, "/", "\\");
  57. str << " Delete \"$INSTDIR\\" << fileN.c_str() << "\"" << std::endl;
  58. }
  59. cmCPackLogger(cmCPackLog::LOG_DEBUG, "Uninstall Files: "
  60. << str.str().c_str() << std::endl);
  61. this->SetOption("CPACK_NSIS_DELETE_FILES", str.str().c_str());
  62. std::vector<std::string> dirs;
  63. this->GetListOfSubdirectories(toplevel, dirs);
  64. std::vector<std::string>::const_iterator sit;
  65. cmOStringStream dstr;
  66. for ( sit = dirs.begin(); sit != dirs.end(); ++ sit )
  67. {
  68. std::string fileN = cmSystemTools::RelativePath(toplevel,
  69. sit->c_str());
  70. if ( fileN.empty() )
  71. {
  72. continue;
  73. }
  74. cmSystemTools::ReplaceString(fileN, "/", "\\");
  75. dstr << " RMDir \"$INSTDIR\\" << fileN.c_str() << "\"" << std::endl;
  76. }
  77. cmCPackLogger(cmCPackLog::LOG_DEBUG, "Uninstall Dirs: "
  78. << dstr.str().c_str() << std::endl);
  79. this->SetOption("CPACK_NSIS_DELETE_DIRECTORIES", dstr.str().c_str());
  80. cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Configure file: " << nsisInFileName
  81. << " to " << nsisFileName << std::endl);
  82. this->ConfigureFile(nsisInFileName.c_str(), nsisFileName.c_str());
  83. std::string nsisCmd = "\"";
  84. nsisCmd += this->GetOption("CPACK_INSTALLER_PROGRAM");
  85. nsisCmd += "\" \"" + nsisFileName + "\"";
  86. cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Execute: " << nsisCmd.c_str()
  87. << std::endl);
  88. std::string output;
  89. int retVal = 1;
  90. bool res = cmSystemTools::RunSingleCommand(nsisCmd.c_str(), &output,
  91. &retVal, 0, this->GeneratorVerbose, 0);
  92. if ( !res || retVal )
  93. {
  94. cmGeneratedFileStream ofs(tmpFile.c_str());
  95. ofs << "# Run command: " << nsisCmd.c_str() << std::endl
  96. << "# Output:" << std::endl
  97. << output.c_str() << std::endl;
  98. cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem running NSIS command: "
  99. << nsisCmd.c_str() << std::endl
  100. << "Please check " << tmpFile.c_str() << " for errors" << std::endl);
  101. return 0;
  102. }
  103. return 1;
  104. }
  105. //----------------------------------------------------------------------
  106. int cmCPackNSISGenerator::InitializeInternal()
  107. {
  108. if ( cmSystemTools::IsOn(this->GetOption(
  109. "CPACK_INCLUDE_TOPLEVEL_DIRECTORY")) )
  110. {
  111. cmCPackLogger(cmCPackLog::LOG_ERROR,
  112. "NSIS Generator cannot work with CPACK_INCLUDE_TOPLEVEL_DIRECTORY. "
  113. "This option will be ignored."
  114. << std::endl);
  115. this->SetOption("CPACK_INCLUDE_TOPLEVEL_DIRECTORY", 0);
  116. }
  117. cmCPackLogger(cmCPackLog::LOG_DEBUG, "cmCPackNSISGenerator::Initialize()"
  118. << std::endl);
  119. std::vector<std::string> path;
  120. std::string nsisPath;
  121. if ( !cmsys::SystemTools::ReadRegistryValue(
  122. "HKEY_LOCAL_MACHINE\\SOFTWARE\\NSIS", nsisPath) )
  123. {
  124. cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot find NSIS registry value"
  125. << std::endl);
  126. return 0;
  127. }
  128. path.push_back(nsisPath);
  129. nsisPath = cmSystemTools::FindProgram("makensis", path, false);
  130. if ( nsisPath.empty() )
  131. {
  132. cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot find NSIS compiler"
  133. << std::endl);
  134. return 0;
  135. }
  136. std::string nsisCmd = "\"" + nsisPath + "\" /VERSION";
  137. cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Test NSIS version: "
  138. << nsisCmd.c_str() << std::endl);
  139. std::string output;
  140. int retVal = 1;
  141. bool resS = cmSystemTools::RunSingleCommand(nsisCmd.c_str(),
  142. &output, &retVal, 0, this->GeneratorVerbose, 0);
  143. cmsys::RegularExpression versionRex("v([0-9]+.[0-9]+)");
  144. if ( !resS || retVal || !versionRex.find(output))
  145. {
  146. std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
  147. tmpFile += "/NSISOutput.log";
  148. cmGeneratedFileStream ofs(tmpFile.c_str());
  149. ofs << "# Run command: " << nsisCmd.c_str() << std::endl
  150. << "# Output:" << std::endl
  151. << output.c_str() << std::endl;
  152. cmCPackLogger(cmCPackLog::LOG_ERROR,
  153. "Problem checking NSIS version with command: "
  154. << nsisCmd.c_str() << std::endl
  155. << "Please check " << tmpFile.c_str() << " for errors" << std::endl);
  156. return 0;
  157. }
  158. float nsisVersion = atof(versionRex.match(1).c_str());
  159. float minNSISVersion = 2.09;
  160. cmCPackLogger(cmCPackLog::LOG_DEBUG, "NSIS Version: "
  161. << nsisVersion << std::endl);
  162. if ( nsisVersion < minNSISVersion )
  163. {
  164. cmCPackLogger(cmCPackLog::LOG_ERROR,
  165. "CPack requires NSIS Version 2.09 or greater. NSIS found on the system "
  166. "was: "
  167. << nsisVersion << std::endl);
  168. return 0;
  169. }
  170. this->SetOption("CPACK_INSTALLER_PROGRAM", nsisPath.c_str());
  171. const char* cpackPackageExecutables
  172. = this->GetOption("CPACK_PACKAGE_EXECUTABLES");
  173. if ( cpackPackageExecutables )
  174. {
  175. cmCPackLogger(cmCPackLog::LOG_DEBUG, "The cpackPackageExecutables: "
  176. << cpackPackageExecutables << "." << std::endl);
  177. cmOStringStream str;
  178. cmOStringStream deleteStr;
  179. std::vector<std::string> cpackPackageExecutablesVector;
  180. cmSystemTools::ExpandListArgument(cpackPackageExecutables,
  181. cpackPackageExecutablesVector);
  182. if ( cpackPackageExecutablesVector.size() % 2 != 0 )
  183. {
  184. cmCPackLogger(cmCPackLog::LOG_ERROR,
  185. "CPACK_PACKAGE_EXECUTABLES should contain pairs of <executable> and "
  186. "<icon name>." << std::endl);
  187. return 0;
  188. }
  189. std::vector<std::string>::iterator it;
  190. for ( it = cpackPackageExecutablesVector.begin();
  191. it != cpackPackageExecutablesVector.end();
  192. ++it )
  193. {
  194. std::string execName = *it;
  195. ++ it;
  196. std::string linkName = *it;
  197. str << " CreateShortCut \"$SMPROGRAMS\\$STARTMENU_FOLDER\\"
  198. << linkName << ".lnk\" \"$INSTDIR\\bin\\" << execName << ".exe\""
  199. << std::endl;
  200. deleteStr << " Delete \"$SMPROGRAMS\\$MUI_TEMP\\" << linkName
  201. << ".lnk\"" << std::endl;
  202. }
  203. this->SetOption("CPACK_NSIS_CREATE_ICONS", str.str().c_str());
  204. this->SetOption("CPACK_NSIS_DELETE_ICONS", deleteStr.str().c_str());
  205. }
  206. return this->Superclass::InitializeInternal();
  207. }
  208. //----------------------------------------------------------------------
  209. bool cmCPackNSISGenerator::GetListOfSubdirectories(const char* topdir,
  210. std::vector<std::string>& dirs)
  211. {
  212. cmsys::Directory dir;
  213. dir.Load(topdir);
  214. size_t fileNum;
  215. for (fileNum = 0; fileNum < dir.GetNumberOfFiles(); ++fileNum)
  216. {
  217. if (strcmp(dir.GetFile(static_cast<unsigned long>(fileNum)),".") &&
  218. strcmp(dir.GetFile(static_cast<unsigned long>(fileNum)),".."))
  219. {
  220. kwsys_stl::string fullPath = topdir;
  221. fullPath += "/";
  222. fullPath += dir.GetFile(static_cast<unsigned long>(fileNum));
  223. if(cmsys::SystemTools::FileIsDirectory(fullPath.c_str()) &&
  224. !cmsys::SystemTools::FileIsSymlink(fullPath.c_str()))
  225. {
  226. if (!this->GetListOfSubdirectories(fullPath.c_str(), dirs))
  227. {
  228. return false;
  229. }
  230. }
  231. }
  232. }
  233. dirs.push_back(topdir);
  234. return true;
  235. }