cmLocalVisualStudioGenerator.cxx 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. /*============================================================================
  2. CMake - Cross Platform Makefile Generator
  3. Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
  4. Distributed under the OSI-approved BSD License (the "License");
  5. see accompanying file Copyright.txt for details.
  6. This software is distributed WITHOUT ANY WARRANTY; without even the
  7. implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  8. See the License for more information.
  9. ============================================================================*/
  10. #include "cmLocalVisualStudioGenerator.h"
  11. #include "cmGlobalGenerator.h"
  12. #include "cmMakefile.h"
  13. #include "cmSourceFile.h"
  14. #include "cmSystemTools.h"
  15. #include "cmCustomCommandGenerator.h"
  16. #include "windows.h"
  17. //----------------------------------------------------------------------------
  18. cmLocalVisualStudioGenerator::cmLocalVisualStudioGenerator()
  19. {
  20. this->WindowsShell = true;
  21. this->WindowsVSIDE = true;
  22. }
  23. //----------------------------------------------------------------------------
  24. cmLocalVisualStudioGenerator::~cmLocalVisualStudioGenerator()
  25. {
  26. }
  27. //----------------------------------------------------------------------------
  28. cmsys::auto_ptr<cmCustomCommand>
  29. cmLocalVisualStudioGenerator::MaybeCreateImplibDir(cmTarget& target,
  30. const char* config)
  31. {
  32. cmsys::auto_ptr<cmCustomCommand> pcc;
  33. // If an executable exports symbols then VS wants to create an
  34. // import library but forgets to create the output directory.
  35. if(target.GetType() != cmTarget::EXECUTABLE) { return pcc; }
  36. std::string outDir = target.GetDirectory(config, false);
  37. std::string impDir = target.GetDirectory(config, true);
  38. if(impDir == outDir) { return pcc; }
  39. // Add a pre-build event to create the directory.
  40. cmCustomCommandLine command;
  41. command.push_back(this->Makefile->GetRequiredDefinition("CMAKE_COMMAND"));
  42. command.push_back("-E");
  43. command.push_back("make_directory");
  44. command.push_back(impDir);
  45. std::vector<std::string> no_output;
  46. std::vector<std::string> no_depends;
  47. cmCustomCommandLines commands;
  48. commands.push_back(command);
  49. pcc.reset(new cmCustomCommand(no_output, no_depends, commands, 0, 0));
  50. pcc->SetEscapeOldStyle(false);
  51. pcc->SetEscapeAllowMakeVars(true);
  52. return pcc;
  53. }
  54. //----------------------------------------------------------------------------
  55. bool cmLocalVisualStudioGenerator::SourceFileCompiles(const cmSourceFile* sf)
  56. {
  57. // Identify the language of the source file.
  58. if(const char* lang = this->GetSourceFileLanguage(*sf))
  59. {
  60. // Check whether this source will actually be compiled.
  61. return (!sf->GetCustomCommand() &&
  62. !sf->GetPropertyAsBool("HEADER_FILE_ONLY") &&
  63. !sf->GetPropertyAsBool("EXTERNAL_OBJECT"));
  64. }
  65. else
  66. {
  67. // Unknown source file language. Assume it will not be compiled.
  68. return false;
  69. }
  70. }
  71. //----------------------------------------------------------------------------
  72. void cmLocalVisualStudioGenerator::CountObjectNames(
  73. const std::vector<cmSourceGroup>& groups,
  74. std::map<cmStdString, int>& counts)
  75. {
  76. for(unsigned int i = 0; i < groups.size(); ++i)
  77. {
  78. cmSourceGroup sg = groups[i];
  79. std::vector<const cmSourceFile*> const& srcs = sg.GetSourceFiles();
  80. for(std::vector<const cmSourceFile*>::const_iterator s = srcs.begin();
  81. s != srcs.end(); ++s)
  82. {
  83. const cmSourceFile* sf = *s;
  84. if(this->SourceFileCompiles(sf))
  85. {
  86. std::string objectName = cmSystemTools::LowerCase(
  87. cmSystemTools::GetFilenameWithoutLastExtension(
  88. sf->GetFullPath()));
  89. objectName += ".obj";
  90. counts[objectName] += 1;
  91. }
  92. }
  93. this->CountObjectNames(sg.GetGroupChildren(), counts);
  94. }
  95. }
  96. //----------------------------------------------------------------------------
  97. void cmLocalVisualStudioGenerator::InsertNeedObjectNames(
  98. const std::vector<cmSourceGroup>& groups,
  99. std::map<cmStdString, int>& count)
  100. {
  101. for(unsigned int i = 0; i < groups.size(); ++i)
  102. {
  103. cmSourceGroup sg = groups[i];
  104. std::vector<const cmSourceFile*> const& srcs = sg.GetSourceFiles();
  105. for(std::vector<const cmSourceFile*>::const_iterator s = srcs.begin();
  106. s != srcs.end(); ++s)
  107. {
  108. const cmSourceFile* sf = *s;
  109. if(this->SourceFileCompiles(sf))
  110. {
  111. std::string objectName = cmSystemTools::LowerCase(
  112. cmSystemTools::GetFilenameWithoutLastExtension(sf->GetFullPath()));
  113. objectName += ".obj";
  114. if(count[objectName] > 1)
  115. {
  116. this->NeedObjectName.insert(sf);
  117. }
  118. }
  119. }
  120. this->InsertNeedObjectNames(sg.GetGroupChildren(), count);
  121. }
  122. }
  123. //----------------------------------------------------------------------------
  124. void cmLocalVisualStudioGenerator::ComputeObjectNameRequirements
  125. (std::vector<cmSourceGroup> const& sourceGroups)
  126. {
  127. // Clear the current set of requirements.
  128. this->NeedObjectName.clear();
  129. // Count the number of object files with each name. Note that
  130. // windows file names are not case sensitive.
  131. std::map<cmStdString, int> objectNameCounts;
  132. this->CountObjectNames(sourceGroups, objectNameCounts);
  133. // For all source files producing duplicate names we need unique
  134. // object name computation.
  135. this->InsertNeedObjectNames(sourceGroups, objectNameCounts);
  136. }
  137. //----------------------------------------------------------------------------
  138. std::string cmLocalVisualStudioGenerator::CheckForErrorLine()
  139. {
  140. return "if errorlevel 1 goto :VCReportError";
  141. }
  142. //----------------------------------------------------------------------------
  143. std::string cmLocalVisualStudioGenerator::GetCheckForErrorLine()
  144. {
  145. return this->CheckForErrorLine();
  146. }
  147. //----------------------------------------------------------------------------
  148. std::string
  149. cmLocalVisualStudioGenerator
  150. ::ConstructScript(cmCustomCommand const& cc,
  151. const char* configName,
  152. const char* newline_text)
  153. {
  154. const cmCustomCommandLines& commandLines = cc.GetCommandLines();
  155. const char* workingDirectory = cc.GetWorkingDirectory();
  156. cmCustomCommandGenerator ccg(cc, configName, this->Makefile);
  157. RelativeRoot relativeRoot = workingDirectory? NONE : START_OUTPUT;
  158. // Avoid leading or trailing newlines.
  159. const char* newline = "";
  160. // Store the script in a string.
  161. std::string script;
  162. if(workingDirectory)
  163. {
  164. // Change the working directory.
  165. script += newline;
  166. newline = newline_text;
  167. script += "cd ";
  168. script += this->Convert(workingDirectory, FULL, SHELL);
  169. // Change the working drive.
  170. if(workingDirectory[0] && workingDirectory[1] == ':')
  171. {
  172. script += newline;
  173. newline = newline_text;
  174. script += workingDirectory[0];
  175. script += workingDirectory[1];
  176. }
  177. }
  178. // for visual studio IDE add extra stuff to the PATH
  179. // if CMAKE_MSVCIDE_RUN_PATH is set.
  180. if(this->Makefile->GetDefinition("MSVC_IDE"))
  181. {
  182. const char* extraPath =
  183. this->Makefile->GetDefinition("CMAKE_MSVCIDE_RUN_PATH");
  184. if(extraPath)
  185. {
  186. script += newline;
  187. newline = newline_text;
  188. script += "set PATH=";
  189. script += extraPath;
  190. script += ";%PATH%";
  191. }
  192. }
  193. // Write each command on a single line.
  194. for(unsigned int c = 0; c < ccg.GetNumberOfCommands(); ++c)
  195. {
  196. // Start a new line.
  197. script += newline;
  198. newline = newline_text;
  199. // Add this command line.
  200. std::string cmd = ccg.GetCommand(c);
  201. script += this->Convert(cmd.c_str(), relativeRoot, SHELL);
  202. ccg.AppendArguments(c, script);
  203. // After each custom command, check for an error result.
  204. // If there was an error, jump to the VCReportError label,
  205. // skipping the run of any subsequent commands in this
  206. // sequence.
  207. //
  208. script += newline_text;
  209. script += this->GetCheckForErrorLine();
  210. }
  211. return script;
  212. }