cmLocalVisualStudioGenerator.cxx 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  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 "cmLocalVisualStudioGenerator.h"
  14. #include "cmGlobalGenerator.h"
  15. #include "cmMakefile.h"
  16. #include "cmSourceFile.h"
  17. #include "cmSystemTools.h"
  18. #include "windows.h"
  19. //----------------------------------------------------------------------------
  20. cmLocalVisualStudioGenerator::cmLocalVisualStudioGenerator()
  21. {
  22. this->WindowsShell = true;
  23. this->WindowsVSIDE = true;
  24. this->NeedXMLEscape = false;
  25. }
  26. //----------------------------------------------------------------------------
  27. cmLocalVisualStudioGenerator::~cmLocalVisualStudioGenerator()
  28. {
  29. }
  30. //----------------------------------------------------------------------------
  31. cmsys::auto_ptr<cmCustomCommand>
  32. cmLocalVisualStudioGenerator::MaybeCreateImplibDir(cmTarget& target,
  33. const char* config)
  34. {
  35. cmsys::auto_ptr<cmCustomCommand> pcc;
  36. // If an executable exports symbols then VS wants to create an
  37. // import library but forgets to create the output directory.
  38. if(target.GetType() != cmTarget::EXECUTABLE) { return pcc; }
  39. std::string outDir = target.GetDirectory(config, false);
  40. std::string impDir = target.GetDirectory(config, true);
  41. if(impDir == outDir) { return pcc; }
  42. // Add a pre-build event to create the directory.
  43. cmCustomCommandLine command;
  44. command.push_back(this->Makefile->GetRequiredDefinition("CMAKE_COMMAND"));
  45. command.push_back("-E");
  46. command.push_back("make_directory");
  47. command.push_back(impDir);
  48. std::vector<std::string> no_output;
  49. std::vector<std::string> no_depends;
  50. cmCustomCommandLines commands;
  51. commands.push_back(command);
  52. pcc.reset(new cmCustomCommand(no_output, no_depends, commands, 0, 0));
  53. pcc->SetEscapeOldStyle(false);
  54. pcc->SetEscapeAllowMakeVars(true);
  55. return pcc;
  56. }
  57. //----------------------------------------------------------------------------
  58. bool cmLocalVisualStudioGenerator::SourceFileCompiles(const cmSourceFile* sf)
  59. {
  60. // Identify the language of the source file.
  61. if(const char* lang = this->GetSourceFileLanguage(*sf))
  62. {
  63. // Check whether this source will actually be compiled.
  64. return (!sf->GetCustomCommand() &&
  65. !sf->GetPropertyAsBool("HEADER_FILE_ONLY") &&
  66. !sf->GetPropertyAsBool("EXTERNAL_OBJECT"));
  67. }
  68. else
  69. {
  70. // Unknown source file language. Assume it will not be compiled.
  71. return false;
  72. }
  73. }
  74. //----------------------------------------------------------------------------
  75. void cmLocalVisualStudioGenerator::CountObjectNames(
  76. const std::vector<cmSourceGroup>& groups,
  77. std::map<cmStdString, int>& counts)
  78. {
  79. for(unsigned int i = 0; i < groups.size(); ++i)
  80. {
  81. cmSourceGroup sg = groups[i];
  82. std::vector<const cmSourceFile*> const& srcs = sg.GetSourceFiles();
  83. for(std::vector<const cmSourceFile*>::const_iterator s = srcs.begin();
  84. s != srcs.end(); ++s)
  85. {
  86. const cmSourceFile* sf = *s;
  87. if(this->SourceFileCompiles(sf))
  88. {
  89. std::string objectName = cmSystemTools::LowerCase(
  90. cmSystemTools::GetFilenameWithoutLastExtension(
  91. sf->GetFullPath()));
  92. objectName += ".obj";
  93. counts[objectName] += 1;
  94. }
  95. }
  96. this->CountObjectNames(sg.GetGroupChildren(), counts);
  97. }
  98. }
  99. //----------------------------------------------------------------------------
  100. void cmLocalVisualStudioGenerator::InsertNeedObjectNames(
  101. const std::vector<cmSourceGroup>& groups,
  102. std::map<cmStdString, int>& count)
  103. {
  104. for(unsigned int i = 0; i < groups.size(); ++i)
  105. {
  106. cmSourceGroup sg = groups[i];
  107. std::vector<const cmSourceFile*> const& srcs = sg.GetSourceFiles();
  108. for(std::vector<const cmSourceFile*>::const_iterator s = srcs.begin();
  109. s != srcs.end(); ++s)
  110. {
  111. const cmSourceFile* sf = *s;
  112. if(this->SourceFileCompiles(sf))
  113. {
  114. std::string objectName = cmSystemTools::LowerCase(
  115. cmSystemTools::GetFilenameWithoutLastExtension(sf->GetFullPath()));
  116. objectName += ".obj";
  117. if(count[objectName] > 1)
  118. {
  119. this->NeedObjectName.insert(sf);
  120. }
  121. }
  122. }
  123. this->InsertNeedObjectNames(sg.GetGroupChildren(), count);
  124. }
  125. }
  126. //----------------------------------------------------------------------------
  127. void cmLocalVisualStudioGenerator::ComputeObjectNameRequirements
  128. (std::vector<cmSourceGroup> const& sourceGroups)
  129. {
  130. // Clear the current set of requirements.
  131. this->NeedObjectName.clear();
  132. // Count the number of object files with each name. Note that
  133. // windows file names are not case sensitive.
  134. std::map<cmStdString, int> objectNameCounts;
  135. this->CountObjectNames(sourceGroups, objectNameCounts);
  136. // For all source files producing duplicate names we need unique
  137. // object name computation.
  138. this->InsertNeedObjectNames(sourceGroups, objectNameCounts);
  139. }
  140. //----------------------------------------------------------------------------
  141. std::string
  142. cmLocalVisualStudioGenerator
  143. ::ConstructScript(const cmCustomCommandLines& commandLines,
  144. const char* workingDirectory,
  145. const char* configName,
  146. bool escapeOldStyle,
  147. bool escapeAllowMakeVars,
  148. const char* newline_text)
  149. {
  150. // Avoid leading or trailing newlines.
  151. const char* newline = "";
  152. // Store the script in a string.
  153. std::string script;
  154. if(workingDirectory)
  155. {
  156. // Change the working directory.
  157. script += newline;
  158. newline = newline_text;
  159. script += "cd ";
  160. script += this->Convert(workingDirectory, START_OUTPUT, SHELL);
  161. // Change the working drive.
  162. if(workingDirectory[0] && workingDirectory[1] == ':')
  163. {
  164. script += newline;
  165. newline = newline_text;
  166. script += workingDirectory[0];
  167. script += workingDirectory[1];
  168. }
  169. }
  170. // for visual studio IDE add extra stuff to the PATH
  171. // if CMAKE_MSVCIDE_RUN_PATH is set.
  172. if(this->Makefile->GetDefinition("MSVC_IDE"))
  173. {
  174. const char* extraPath =
  175. this->Makefile->GetDefinition("CMAKE_MSVCIDE_RUN_PATH");
  176. if(extraPath)
  177. {
  178. script += newline;
  179. newline = newline_text;
  180. script += "set PATH=";
  181. script += extraPath;
  182. script += ";%PATH%";
  183. }
  184. }
  185. // Write each command on a single line.
  186. for(cmCustomCommandLines::const_iterator cl = commandLines.begin();
  187. cl != commandLines.end(); ++cl)
  188. {
  189. // Start a new line.
  190. script += newline;
  191. newline = newline_text;
  192. // Start with the command name.
  193. const cmCustomCommandLine& commandLine = *cl;
  194. std::string commandName = this->GetRealLocation(commandLine[0].c_str(),
  195. configName);
  196. if(!workingDirectory)
  197. {
  198. script += this->Convert(commandName.c_str(),START_OUTPUT,SHELL);
  199. }
  200. else
  201. {
  202. script += this->Convert(commandName.c_str(),NONE,SHELL);
  203. }
  204. // Add the arguments.
  205. for(unsigned int j=1;j < commandLine.size(); ++j)
  206. {
  207. script += " ";
  208. if(escapeOldStyle)
  209. {
  210. script += this->EscapeForShellOldStyle(commandLine[j].c_str());
  211. }
  212. else
  213. {
  214. if(this->NeedXMLEscape)
  215. {
  216. std::string arg = commandLine[j];
  217. cmSystemTools::ReplaceString(arg, "&", "&amp;");
  218. cmSystemTools::ReplaceString(arg, "<", "&lt;");
  219. cmSystemTools::ReplaceString(arg, ">", "&gt;");
  220. if(arg.find(" ") != arg.npos)
  221. {
  222. std::string q("\"");
  223. arg = q + arg +q;
  224. }
  225. script += arg;
  226. //script += this->EscapeForShell(arg.c_str(),
  227. //escapeAllowMakeVars);
  228. }
  229. else
  230. {
  231. script += this->EscapeForShell(commandLine[j].c_str(),
  232. escapeAllowMakeVars);
  233. }
  234. }
  235. }
  236. }
  237. return script;
  238. }