cmExportBuildFileGenerator.cxx 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  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 "cmExportBuildFileGenerator.h"
  11. #include "cmLocalGenerator.h"
  12. #include "cmGlobalGenerator.h"
  13. #include "cmExportSet.h"
  14. #include "cmTargetExport.h"
  15. //----------------------------------------------------------------------------
  16. cmExportBuildFileGenerator::cmExportBuildFileGenerator()
  17. {
  18. this->LG = 0;
  19. this->ExportSet = 0;
  20. }
  21. //----------------------------------------------------------------------------
  22. void cmExportBuildFileGenerator::Compute(cmLocalGenerator* lg)
  23. {
  24. this->LG = lg;
  25. }
  26. //----------------------------------------------------------------------------
  27. bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os)
  28. {
  29. std::vector<cmGeneratorTarget*> allTargets;
  30. {
  31. std::string expectedTargets;
  32. std::string sep;
  33. std::vector<std::string> targets;
  34. this->GetTargets(targets);
  35. for(std::vector<std::string>::const_iterator
  36. tei = targets.begin();
  37. tei != targets.end(); ++tei)
  38. {
  39. cmGeneratorTarget *te = this->LG->GetMakefile()
  40. ->FindGeneratorTargetToUse(*tei);
  41. expectedTargets += sep + this->Namespace + te->Target->GetExportName();
  42. sep = " ";
  43. if(this->ExportedTargets.insert(te->Target).second)
  44. {
  45. this->Exports.push_back(te);
  46. }
  47. else
  48. {
  49. std::ostringstream e;
  50. e << "given target \"" << te->GetName() << "\" more than once.";
  51. this->LG->GetGlobalGenerator()->GetCMakeInstance()
  52. ->IssueMessage(cmake::FATAL_ERROR, e.str(),
  53. this->LG->GetMakefile()->GetBacktrace());
  54. return false;
  55. }
  56. if (te->GetType() == cmTarget::INTERFACE_LIBRARY)
  57. {
  58. this->GenerateRequiredCMakeVersion(os, "3.0.0");
  59. }
  60. }
  61. this->GenerateExpectedTargetsCode(os, expectedTargets);
  62. }
  63. std::vector<std::string> missingTargets;
  64. // Create all the imported targets.
  65. for(std::vector<cmGeneratorTarget*>::const_iterator
  66. tei = this->Exports.begin();
  67. tei != this->Exports.end(); ++tei)
  68. {
  69. cmGeneratorTarget* gte = *tei;
  70. cmTarget* te = gte->Target;
  71. this->GenerateImportTargetCode(os, te);
  72. te->AppendBuildInterfaceIncludes();
  73. ImportPropertyMap properties;
  74. this->PopulateInterfaceProperty("INTERFACE_INCLUDE_DIRECTORIES", te,
  75. cmGeneratorExpression::BuildInterface,
  76. properties, missingTargets);
  77. this->PopulateInterfaceProperty("INTERFACE_SOURCES", te,
  78. cmGeneratorExpression::BuildInterface,
  79. properties, missingTargets);
  80. this->PopulateInterfaceProperty("INTERFACE_COMPILE_DEFINITIONS", te,
  81. cmGeneratorExpression::BuildInterface,
  82. properties, missingTargets);
  83. this->PopulateInterfaceProperty("INTERFACE_COMPILE_OPTIONS", te,
  84. cmGeneratorExpression::BuildInterface,
  85. properties, missingTargets);
  86. this->PopulateInterfaceProperty("INTERFACE_AUTOUIC_OPTIONS", te,
  87. cmGeneratorExpression::BuildInterface,
  88. properties, missingTargets);
  89. this->PopulateInterfaceProperty("INTERFACE_COMPILE_FEATURES", te,
  90. cmGeneratorExpression::BuildInterface,
  91. properties, missingTargets);
  92. this->PopulateInterfaceProperty("INTERFACE_POSITION_INDEPENDENT_CODE",
  93. te, properties);
  94. const bool newCMP0022Behavior =
  95. te->GetPolicyStatusCMP0022() != cmPolicies::WARN
  96. && te->GetPolicyStatusCMP0022() != cmPolicies::OLD;
  97. if (newCMP0022Behavior)
  98. {
  99. this->PopulateInterfaceLinkLibrariesProperty(te,
  100. cmGeneratorExpression::BuildInterface,
  101. properties, missingTargets);
  102. }
  103. this->PopulateCompatibleInterfaceProperties(gte, properties);
  104. this->GenerateInterfaceProperties(te, os, properties);
  105. }
  106. // Generate import file content for each configuration.
  107. for(std::vector<std::string>::const_iterator
  108. ci = this->Configurations.begin();
  109. ci != this->Configurations.end(); ++ci)
  110. {
  111. this->GenerateImportConfig(os, *ci, missingTargets);
  112. }
  113. this->GenerateMissingTargetsCheckCode(os, missingTargets);
  114. return true;
  115. }
  116. //----------------------------------------------------------------------------
  117. void
  118. cmExportBuildFileGenerator
  119. ::GenerateImportTargetsConfig(std::ostream& os,
  120. const std::string& config,
  121. std::string const& suffix,
  122. std::vector<std::string> &missingTargets)
  123. {
  124. for(std::vector<cmGeneratorTarget*>::const_iterator
  125. tei = this->Exports.begin();
  126. tei != this->Exports.end(); ++tei)
  127. {
  128. // Collect import properties for this target.
  129. cmGeneratorTarget* target = *tei;
  130. ImportPropertyMap properties;
  131. if (target->GetType() != cmTarget::INTERFACE_LIBRARY)
  132. {
  133. this->SetImportLocationProperty(config, suffix, target, properties);
  134. }
  135. if(!properties.empty())
  136. {
  137. // Get the rest of the target details.
  138. if (target->GetType() != cmTarget::INTERFACE_LIBRARY)
  139. {
  140. this->SetImportDetailProperties(config, suffix,
  141. target,
  142. properties, missingTargets);
  143. this->SetImportLinkInterface(config, suffix,
  144. cmGeneratorExpression::BuildInterface,
  145. target,
  146. properties, missingTargets);
  147. }
  148. // TOOD: PUBLIC_HEADER_LOCATION
  149. // This should wait until the build feature propagation stuff
  150. // is done. Then this can be a propagated include directory.
  151. // this->GenerateImportProperty(config, te->HeaderGenerator,
  152. // properties);
  153. // Generate code in the export file.
  154. this->GenerateImportPropertyCode(os, config, target->Target,
  155. properties);
  156. }
  157. }
  158. }
  159. //----------------------------------------------------------------------------
  160. void cmExportBuildFileGenerator::SetExportSet(cmExportSet *exportSet)
  161. {
  162. this->ExportSet = exportSet;
  163. }
  164. //----------------------------------------------------------------------------
  165. void
  166. cmExportBuildFileGenerator
  167. ::SetImportLocationProperty(const std::string& config,
  168. std::string const& suffix,
  169. cmGeneratorTarget* target,
  170. ImportPropertyMap& properties)
  171. {
  172. // Get the makefile in which to lookup target information.
  173. cmMakefile* mf = target->Makefile;
  174. // Add the main target file.
  175. {
  176. std::string prop = "IMPORTED_LOCATION";
  177. prop += suffix;
  178. std::string value;
  179. if(target->Target->IsAppBundleOnApple())
  180. {
  181. value = target->GetFullPath(config, false);
  182. }
  183. else
  184. {
  185. value = target->GetFullPath(config, false, true);
  186. }
  187. properties[prop] = value;
  188. }
  189. // Check whether this is a DLL platform.
  190. bool dll_platform =
  191. (mf->IsOn("WIN32") || mf->IsOn("CYGWIN") || mf->IsOn("MINGW"));
  192. // Add the import library for windows DLLs.
  193. if(dll_platform &&
  194. (target->GetType() == cmTarget::SHARED_LIBRARY ||
  195. target->Target->IsExecutableWithExports()) &&
  196. mf->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX"))
  197. {
  198. std::string prop = "IMPORTED_IMPLIB";
  199. prop += suffix;
  200. std::string value = target->GetFullPath(config, true);
  201. target->GetImplibGNUtoMS(value, value,
  202. "${CMAKE_IMPORT_LIBRARY_SUFFIX}");
  203. properties[prop] = value;
  204. }
  205. }
  206. //----------------------------------------------------------------------------
  207. void
  208. cmExportBuildFileGenerator::HandleMissingTarget(
  209. std::string& link_libs, std::vector<std::string>& missingTargets,
  210. cmMakefile* mf, cmTarget* depender, cmTarget* dependee)
  211. {
  212. // The target is not in the export.
  213. if(!this->AppendMode)
  214. {
  215. const std::string name = dependee->GetName();
  216. std::vector<std::string> namespaces = this->FindNamespaces(mf, name);
  217. int targetOccurrences = (int)namespaces.size();
  218. if (targetOccurrences == 1)
  219. {
  220. std::string missingTarget = namespaces[0];
  221. missingTarget += dependee->GetExportName();
  222. link_libs += missingTarget;
  223. missingTargets.push_back(missingTarget);
  224. return;
  225. }
  226. else
  227. {
  228. // We are not appending, so all exported targets should be
  229. // known here. This is probably user-error.
  230. this->ComplainAboutMissingTarget(depender, dependee, targetOccurrences);
  231. }
  232. }
  233. // Assume the target will be exported by another command.
  234. // Append it with the export namespace.
  235. link_libs += this->Namespace;
  236. link_libs += dependee->GetExportName();
  237. }
  238. //----------------------------------------------------------------------------
  239. void cmExportBuildFileGenerator
  240. ::GetTargets(std::vector<std::string> &targets) const
  241. {
  242. if (this->ExportSet)
  243. {
  244. for(std::vector<cmTargetExport*>::const_iterator
  245. tei = this->ExportSet->GetTargetExports()->begin();
  246. tei != this->ExportSet->GetTargetExports()->end(); ++tei)
  247. {
  248. targets.push_back((*tei)->Target->GetName());
  249. }
  250. return;
  251. }
  252. targets = this->Targets;
  253. }
  254. //----------------------------------------------------------------------------
  255. std::vector<std::string>
  256. cmExportBuildFileGenerator
  257. ::FindNamespaces(cmMakefile* mf, const std::string& name)
  258. {
  259. std::vector<std::string> namespaces;
  260. cmGlobalGenerator* gg = mf->GetGlobalGenerator();
  261. std::map<std::string, cmExportBuildFileGenerator*>& exportSets
  262. = gg->GetBuildExportSets();
  263. for(std::map<std::string, cmExportBuildFileGenerator*>::const_iterator
  264. expIt = exportSets.begin(); expIt != exportSets.end(); ++expIt)
  265. {
  266. const cmExportBuildFileGenerator* exportSet = expIt->second;
  267. std::vector<std::string> targets;
  268. exportSet->GetTargets(targets);
  269. if (std::find(targets.begin(), targets.end(), name) != targets.end())
  270. {
  271. namespaces.push_back(exportSet->GetNamespace());
  272. }
  273. }
  274. return namespaces;
  275. }
  276. //----------------------------------------------------------------------------
  277. void
  278. cmExportBuildFileGenerator
  279. ::ComplainAboutMissingTarget(cmTarget* depender,
  280. cmTarget* dependee,
  281. int occurrences)
  282. {
  283. if(cmSystemTools::GetErrorOccuredFlag())
  284. {
  285. return;
  286. }
  287. std::ostringstream e;
  288. e << "export called with target \"" << depender->GetName()
  289. << "\" which requires target \"" << dependee->GetName() << "\" ";
  290. if (occurrences == 0)
  291. {
  292. e << "that is not in the export set.\n";
  293. }
  294. else
  295. {
  296. e << "that is not in this export set, but " << occurrences
  297. << " times in others.\n";
  298. }
  299. e << "If the required target is not easy to reference in this call, "
  300. << "consider using the APPEND option with multiple separate calls.";
  301. this->LG->GetGlobalGenerator()->GetCMakeInstance()
  302. ->IssueMessage(cmake::FATAL_ERROR, e.str(),
  303. this->LG->GetMakefile()->GetBacktrace());
  304. }
  305. std::string
  306. cmExportBuildFileGenerator::InstallNameDir(cmGeneratorTarget* target,
  307. const std::string& config)
  308. {
  309. std::string install_name_dir;
  310. cmMakefile* mf = target->Target->GetMakefile();
  311. if(mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME"))
  312. {
  313. install_name_dir =
  314. target->GetInstallNameDirForBuildTree(config);
  315. }
  316. return install_name_dir;
  317. }