cmGlobalVisualStudioGenerator.cxx 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  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 "cmGlobalVisualStudioGenerator.h"
  14. #include "cmLocalGenerator.h"
  15. #include "cmMakefile.h"
  16. #include "cmTarget.h"
  17. //----------------------------------------------------------------------------
  18. cmGlobalVisualStudioGenerator::cmGlobalVisualStudioGenerator()
  19. {
  20. }
  21. //----------------------------------------------------------------------------
  22. cmGlobalVisualStudioGenerator::~cmGlobalVisualStudioGenerator()
  23. {
  24. }
  25. //----------------------------------------------------------------------------
  26. void cmGlobalVisualStudioGenerator::Generate()
  27. {
  28. // Add a special target that depends on ALL projects for easy build
  29. // of one configuration only.
  30. const char* no_working_dir = 0;
  31. std::vector<std::string> no_depends;
  32. cmCustomCommandLines no_commands;
  33. std::map<cmStdString, std::vector<cmLocalGenerator*> >::iterator it;
  34. for(it = this->ProjectMap.begin(); it!= this->ProjectMap.end(); ++it)
  35. {
  36. std::vector<cmLocalGenerator*>& gen = it->second;
  37. // add the ALL_BUILD to the first local generator of each project
  38. if(gen.size())
  39. {
  40. // Use no actual command lines so that the target itself is not
  41. // considered always out of date.
  42. gen[0]->GetMakefile()->
  43. AddUtilityCommand("ALL_BUILD", true, no_working_dir,
  44. no_depends, no_commands, false,
  45. "Build all projects");
  46. }
  47. }
  48. // Fix utility dependencies to avoid linking to libraries.
  49. this->FixUtilityDepends();
  50. // Run all the local generators.
  51. this->cmGlobalGenerator::Generate();
  52. }
  53. //----------------------------------------------------------------------------
  54. void cmGlobalVisualStudioGenerator::FixUtilityDepends()
  55. {
  56. // For VS versions before 8:
  57. //
  58. // When a target that links contains a project-level dependency on a
  59. // library target that library is automatically linked. In order to
  60. // allow utility-style project-level dependencies that do not
  61. // actually link we need to automatically insert an intermediate
  62. // custom target.
  63. //
  64. // Here we edit the utility dependencies of a target to add the
  65. // intermediate custom target when necessary.
  66. for(unsigned i = 0; i < this->LocalGenerators.size(); ++i)
  67. {
  68. cmTargets* targets =
  69. &(this->LocalGenerators[i]->GetMakefile()->GetTargets());
  70. for(cmTargets::iterator tarIt = targets->begin();
  71. tarIt != targets->end(); ++tarIt)
  72. {
  73. this->FixUtilityDependsForTarget(tarIt->second);
  74. }
  75. }
  76. }
  77. //----------------------------------------------------------------------------
  78. void
  79. cmGlobalVisualStudioGenerator::FixUtilityDependsForTarget(cmTarget& target)
  80. {
  81. // Only targets that link need to be fixed.
  82. if(target.GetType() != cmTarget::STATIC_LIBRARY &&
  83. target.GetType() != cmTarget::SHARED_LIBRARY &&
  84. target.GetType() != cmTarget::MODULE_LIBRARY &&
  85. target.GetType() != cmTarget::EXECUTABLE)
  86. {
  87. return;
  88. }
  89. // Look at each utility dependency.
  90. for(std::set<cmStdString>::const_iterator ui =
  91. target.GetUtilities().begin();
  92. ui != target.GetUtilities().end(); ++ui)
  93. {
  94. if(cmTarget* depTarget = this->FindTarget(0, ui->c_str(), false))
  95. {
  96. if(depTarget->GetType() == cmTarget::STATIC_LIBRARY ||
  97. depTarget->GetType() == cmTarget::SHARED_LIBRARY ||
  98. depTarget->GetType() == cmTarget::MODULE_LIBRARY)
  99. {
  100. // This utility dependency will cause an attempt to link. If
  101. // the depender does not already link the dependee we need an
  102. // intermediate target.
  103. if(!this->CheckTargetLinks(target, ui->c_str()))
  104. {
  105. this->CreateUtilityDependTarget(*depTarget);
  106. }
  107. }
  108. }
  109. }
  110. }
  111. //----------------------------------------------------------------------------
  112. void
  113. cmGlobalVisualStudioGenerator::CreateUtilityDependTarget(cmTarget& target)
  114. {
  115. // This target is a library on which a utility dependency exists.
  116. // We need to create an intermediate custom target to hook up the
  117. // dependency without causing a link.
  118. const char* altName = target.GetProperty("ALTERNATIVE_DEPENDENCY_NAME");
  119. if(!altName)
  120. {
  121. // Create the intermediate utility target.
  122. std::string altNameStr = target.GetName();
  123. altNameStr += "_UTILITY";
  124. const std::vector<std::string> no_depends;
  125. cmCustomCommandLines no_commands;
  126. const char* no_working_dir = 0;
  127. const char* no_comment = 0;
  128. target.GetMakefile()->AddUtilityCommand(altNameStr.c_str(), true,
  129. no_working_dir, no_depends,
  130. no_commands, false, no_comment);
  131. target.SetProperty("ALTERNATIVE_DEPENDENCY_NAME", altNameStr.c_str());
  132. // Most targets have a GUID created in ConfigureFinalPass. Since
  133. // that has already been called, create one for this target now.
  134. this->CreateGUID(altNameStr.c_str());
  135. // The intermediate target should depend on the original target.
  136. if(cmTarget* alt = this->FindTarget(0, altNameStr.c_str(), false))
  137. {
  138. alt->AddUtility(target.GetName());
  139. }
  140. }
  141. }
  142. //----------------------------------------------------------------------------
  143. bool cmGlobalVisualStudioGenerator::CheckTargetLinks(cmTarget& target,
  144. const char* name)
  145. {
  146. // Return whether the given target links to a target with the given name.
  147. if(target.GetType() == cmTarget::STATIC_LIBRARY)
  148. {
  149. // Static libraries never link to anything.
  150. return false;
  151. }
  152. cmTarget::LinkLibraryVectorType const& libs = target.GetLinkLibraries();
  153. for(cmTarget::LinkLibraryVectorType::const_iterator i = libs.begin();
  154. i != libs.end(); ++i)
  155. {
  156. if(i->first == name)
  157. {
  158. return true;
  159. }
  160. }
  161. return false;
  162. }
  163. //----------------------------------------------------------------------------
  164. const char*
  165. cmGlobalVisualStudioGenerator::GetUtilityForTarget(cmTarget& target,
  166. const char* name)
  167. {
  168. // Handle the external MS project special case.
  169. if(strncmp(name, "INCLUDE_EXTERNAL_MSPROJECT", 26) == 0)
  170. {
  171. // Note from Ken:
  172. // kind of weird removing the first 27 letters. my
  173. // recommendatsions: use cmCustomCommand::GetCommand() to get the
  174. // project name or get rid of the target name starting with
  175. // "INCLUDE_EXTERNAL_MSPROJECT_" and use another indicator/flag
  176. // somewhere. These external project names shouldn't conflict
  177. // with cmake target names anyways.
  178. return name+27;
  179. }
  180. // Possibly depend on an intermediate utility target to avoid
  181. // linking.
  182. if(target.GetType() == cmTarget::STATIC_LIBRARY ||
  183. target.GetType() == cmTarget::SHARED_LIBRARY ||
  184. target.GetType() == cmTarget::MODULE_LIBRARY ||
  185. target.GetType() == cmTarget::EXECUTABLE)
  186. {
  187. // The depender is a target that links. Lookup the dependee to
  188. // see if it provides an alternative dependency name.
  189. if(cmTarget* depTarget = this->FindTarget(0, name, false))
  190. {
  191. // Check for an alternative name created by FixUtilityDepends.
  192. if(const char* altName =
  193. depTarget->GetProperty("ALTERNATIVE_DEPENDENCY_NAME"))
  194. {
  195. // The alternative name is needed only if the depender does
  196. // not really link to the dependee.
  197. if(!this->CheckTargetLinks(target, name))
  198. {
  199. return altName;
  200. }
  201. }
  202. }
  203. }
  204. // No special case. Just use the original dependency name.
  205. return name;
  206. }