cmCPackNSISGenerator.cxx 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  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 nsisInInstallOptions
  47. = this->FindTemplate("NSIS.InstallOptions.ini.in");
  48. if ( nsisInInstallOptions.size() == 0 )
  49. {
  50. cmCPackLogger(cmCPackLog::LOG_ERROR,
  51. "CPack error: Could not find NSIS installer options file."
  52. << std::endl);
  53. return false;
  54. }
  55. std::string nsisFileName = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
  56. std::string tmpFile = nsisFileName;
  57. tmpFile += "/NSISOutput.log";
  58. std::string nsisInstallOptions = nsisFileName + "/NSIS.InstallOptions.ini";
  59. nsisFileName += "/project.nsi";
  60. cmOStringStream str;
  61. std::vector<std::string>::const_iterator it;
  62. for ( it = files.begin(); it != files.end(); ++ it )
  63. {
  64. std::string fileN = cmSystemTools::RelativePath(toplevel,
  65. it->c_str());
  66. cmSystemTools::ReplaceString(fileN, "/", "\\");
  67. str << " Delete \"$INSTDIR\\" << fileN.c_str() << "\"" << std::endl;
  68. }
  69. cmCPackLogger(cmCPackLog::LOG_DEBUG, "Uninstall Files: "
  70. << str.str().c_str() << std::endl);
  71. this->SetOptionIfNotSet("CPACK_NSIS_DELETE_FILES", str.str().c_str());
  72. std::vector<std::string> dirs;
  73. this->GetListOfSubdirectories(toplevel, dirs);
  74. std::vector<std::string>::const_iterator sit;
  75. cmOStringStream dstr;
  76. for ( sit = dirs.begin(); sit != dirs.end(); ++ sit )
  77. {
  78. std::string fileN = cmSystemTools::RelativePath(toplevel,
  79. sit->c_str());
  80. if ( fileN.empty() )
  81. {
  82. continue;
  83. }
  84. cmSystemTools::ReplaceString(fileN, "/", "\\");
  85. dstr << " RMDir \"$INSTDIR\\" << fileN.c_str() << "\"" << std::endl;
  86. }
  87. cmCPackLogger(cmCPackLog::LOG_DEBUG, "Uninstall Dirs: "
  88. << dstr.str().c_str() << std::endl);
  89. this->SetOptionIfNotSet("CPACK_NSIS_DELETE_DIRECTORIES",
  90. dstr.str().c_str());
  91. cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Configure file: " << nsisInFileName
  92. << " to " << nsisFileName << std::endl);
  93. this->ConfigureFile(nsisInInstallOptions.c_str(),
  94. nsisInstallOptions.c_str());
  95. this->ConfigureFile(nsisInFileName.c_str(), nsisFileName.c_str());
  96. std::string nsisCmd = "\"";
  97. nsisCmd += this->GetOption("CPACK_INSTALLER_PROGRAM");
  98. nsisCmd += "\" \"" + nsisFileName + "\"";
  99. cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Execute: " << nsisCmd.c_str()
  100. << std::endl);
  101. std::string output;
  102. int retVal = 1;
  103. bool res = cmSystemTools::RunSingleCommand(nsisCmd.c_str(), &output,
  104. &retVal, 0, this->GeneratorVerbose, 0);
  105. if ( !res || retVal )
  106. {
  107. cmGeneratedFileStream ofs(tmpFile.c_str());
  108. ofs << "# Run command: " << nsisCmd.c_str() << std::endl
  109. << "# Output:" << std::endl
  110. << output.c_str() << std::endl;
  111. cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem running NSIS command: "
  112. << nsisCmd.c_str() << std::endl
  113. << "Please check " << tmpFile.c_str() << " for errors" << std::endl);
  114. return 0;
  115. }
  116. return 1;
  117. }
  118. //----------------------------------------------------------------------
  119. int cmCPackNSISGenerator::InitializeInternal()
  120. {
  121. if ( cmSystemTools::IsOn(this->GetOption(
  122. "CPACK_INCLUDE_TOPLEVEL_DIRECTORY")) )
  123. {
  124. cmCPackLogger(cmCPackLog::LOG_ERROR,
  125. "NSIS Generator cannot work with CPACK_INCLUDE_TOPLEVEL_DIRECTORY. "
  126. "This option will be ignored."
  127. << std::endl);
  128. this->SetOption("CPACK_INCLUDE_TOPLEVEL_DIRECTORY", 0);
  129. }
  130. cmCPackLogger(cmCPackLog::LOG_DEBUG, "cmCPackNSISGenerator::Initialize()"
  131. << std::endl);
  132. std::vector<std::string> path;
  133. std::string nsisPath;
  134. if ( !cmsys::SystemTools::ReadRegistryValue(
  135. "HKEY_LOCAL_MACHINE\\SOFTWARE\\NSIS", nsisPath) )
  136. {
  137. cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot find NSIS registry value"
  138. << std::endl);
  139. return 0;
  140. }
  141. path.push_back(nsisPath);
  142. nsisPath = cmSystemTools::FindProgram("makensis", path, false);
  143. if ( nsisPath.empty() )
  144. {
  145. cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot find NSIS compiler"
  146. << std::endl);
  147. return 0;
  148. }
  149. std::string nsisCmd = "\"" + nsisPath + "\" /VERSION";
  150. cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Test NSIS version: "
  151. << nsisCmd.c_str() << std::endl);
  152. std::string output;
  153. int retVal = 1;
  154. bool resS = cmSystemTools::RunSingleCommand(nsisCmd.c_str(),
  155. &output, &retVal, 0, this->GeneratorVerbose, 0);
  156. cmsys::RegularExpression versionRex("v([0-9]+.[0-9]+)");
  157. if ( !resS || retVal || !versionRex.find(output))
  158. {
  159. std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
  160. tmpFile += "/NSISOutput.log";
  161. cmGeneratedFileStream ofs(tmpFile.c_str());
  162. ofs << "# Run command: " << nsisCmd.c_str() << std::endl
  163. << "# Output:" << std::endl
  164. << output.c_str() << std::endl;
  165. cmCPackLogger(cmCPackLog::LOG_ERROR,
  166. "Problem checking NSIS version with command: "
  167. << nsisCmd.c_str() << std::endl
  168. << "Please check " << tmpFile.c_str() << " for errors" << std::endl);
  169. return 0;
  170. }
  171. float nsisVersion = atof(versionRex.match(1).c_str());
  172. float minNSISVersion = 2.09;
  173. cmCPackLogger(cmCPackLog::LOG_DEBUG, "NSIS Version: "
  174. << nsisVersion << std::endl);
  175. if ( nsisVersion < minNSISVersion )
  176. {
  177. cmCPackLogger(cmCPackLog::LOG_ERROR,
  178. "CPack requires NSIS Version 2.09 or greater. NSIS found on the system "
  179. "was: "
  180. << nsisVersion << std::endl);
  181. return 0;
  182. }
  183. this->SetOptionIfNotSet("CPACK_INSTALLER_PROGRAM", nsisPath.c_str());
  184. const char* cpackPackageExecutables
  185. = this->GetOption("CPACK_PACKAGE_EXECUTABLES");
  186. if ( cpackPackageExecutables )
  187. {
  188. cmCPackLogger(cmCPackLog::LOG_DEBUG, "The cpackPackageExecutables: "
  189. << cpackPackageExecutables << "." << std::endl);
  190. cmOStringStream str;
  191. cmOStringStream deleteStr;
  192. std::vector<std::string> cpackPackageExecutablesVector;
  193. cmSystemTools::ExpandListArgument(cpackPackageExecutables,
  194. cpackPackageExecutablesVector);
  195. if ( cpackPackageExecutablesVector.size() % 2 != 0 )
  196. {
  197. cmCPackLogger(cmCPackLog::LOG_ERROR,
  198. "CPACK_PACKAGE_EXECUTABLES should contain pairs of <executable> and "
  199. "<icon name>." << std::endl);
  200. return 0;
  201. }
  202. std::vector<std::string>::iterator it;
  203. for ( it = cpackPackageExecutablesVector.begin();
  204. it != cpackPackageExecutablesVector.end();
  205. ++it )
  206. {
  207. std::string execName = *it;
  208. ++ it;
  209. std::string linkName = *it;
  210. str << " CreateShortCut \"$SMPROGRAMS\\$STARTMENU_FOLDER\\"
  211. << linkName << ".lnk\" \"$INSTDIR\\bin\\" << execName << ".exe\""
  212. << std::endl;
  213. deleteStr << " Delete \"$SMPROGRAMS\\$MUI_TEMP\\" << linkName
  214. << ".lnk\"" << std::endl;
  215. }
  216. this->SetOptionIfNotSet("CPACK_NSIS_CREATE_ICONS", str.str().c_str());
  217. this->SetOptionIfNotSet("CPACK_NSIS_DELETE_ICONS",
  218. deleteStr.str().c_str());
  219. }
  220. return this->Superclass::InitializeInternal();
  221. }
  222. //----------------------------------------------------------------------
  223. bool cmCPackNSISGenerator::GetListOfSubdirectories(const char* topdir,
  224. std::vector<std::string>& dirs)
  225. {
  226. cmsys::Directory dir;
  227. dir.Load(topdir);
  228. size_t fileNum;
  229. for (fileNum = 0; fileNum < dir.GetNumberOfFiles(); ++fileNum)
  230. {
  231. if (strcmp(dir.GetFile(static_cast<unsigned long>(fileNum)),".") &&
  232. strcmp(dir.GetFile(static_cast<unsigned long>(fileNum)),".."))
  233. {
  234. cmsys_stl::string fullPath = topdir;
  235. fullPath += "/";
  236. fullPath += dir.GetFile(static_cast<unsigned long>(fileNum));
  237. if(cmsys::SystemTools::FileIsDirectory(fullPath.c_str()) &&
  238. !cmsys::SystemTools::FileIsSymlink(fullPath.c_str()))
  239. {
  240. if (!this->GetListOfSubdirectories(fullPath.c_str(), dirs))
  241. {
  242. return false;
  243. }
  244. }
  245. }
  246. }
  247. dirs.push_back(topdir);
  248. return true;
  249. }