cmLocalVisualStudioGenerator.cxx 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  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(0, 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
  139. cmLocalVisualStudioGenerator
  140. ::ConstructScript(cmCustomCommand const& cc,
  141. const char* configName,
  142. const char* newline_text)
  143. {
  144. const cmCustomCommandLines& commandLines = cc.GetCommandLines();
  145. const char* workingDirectory = cc.GetWorkingDirectory();
  146. cmCustomCommandGenerator ccg(cc, configName, this->Makefile);
  147. RelativeRoot relativeRoot = workingDirectory? NONE : START_OUTPUT;
  148. // Avoid leading or trailing newlines.
  149. const char* newline = "";
  150. // Store the script in a string.
  151. std::string script;
  152. if(workingDirectory)
  153. {
  154. // Change the working directory.
  155. script += newline;
  156. newline = newline_text;
  157. script += "cd ";
  158. script += this->Convert(workingDirectory, FULL, SHELL);
  159. // Change the working drive.
  160. if(workingDirectory[0] && workingDirectory[1] == ':')
  161. {
  162. script += newline;
  163. newline = newline_text;
  164. script += workingDirectory[0];
  165. script += workingDirectory[1];
  166. }
  167. }
  168. // for visual studio IDE add extra stuff to the PATH
  169. // if CMAKE_MSVCIDE_RUN_PATH is set.
  170. if(this->Makefile->GetDefinition("MSVC_IDE"))
  171. {
  172. const char* extraPath =
  173. this->Makefile->GetDefinition("CMAKE_MSVCIDE_RUN_PATH");
  174. if(extraPath)
  175. {
  176. script += newline;
  177. newline = newline_text;
  178. script += "set PATH=";
  179. script += extraPath;
  180. script += ";%PATH%";
  181. }
  182. }
  183. // Write each command on a single line.
  184. for(unsigned int c = 0; c < ccg.GetNumberOfCommands(); ++c)
  185. {
  186. // Start a new line.
  187. script += newline;
  188. newline = newline_text;
  189. // Add this command line.
  190. std::string cmd = ccg.GetCommand(c);
  191. script += this->Convert(cmd.c_str(), relativeRoot, SHELL);
  192. ccg.AppendArguments(c, script);
  193. // After each custom command, check for an error result.
  194. // If there was an error, jump to the VCReportError label,
  195. // skipping the run of any subsequent commands in this
  196. // sequence.
  197. //
  198. script += newline_text;
  199. script += "if errorlevel 1 goto VCReportError";
  200. }
  201. return script;
  202. }