cmCommonTargetGenerator.cxx 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. /*============================================================================
  2. CMake - Cross Platform Makefile Generator
  3. Copyright 2000-2015 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 "cmCommonTargetGenerator.h"
  11. #include "cmComputeLinkInformation.h"
  12. #include "cmGeneratorTarget.h"
  13. #include "cmGlobalCommonGenerator.h"
  14. #include "cmLocalCommonGenerator.h"
  15. #include "cmMakefile.h"
  16. #include "cmSourceFile.h"
  17. #include "cmSystemTools.h"
  18. #include "cmTarget.h"
  19. cmCommonTargetGenerator::cmCommonTargetGenerator(
  20. cmOutputConverter::RelativeRoot wd,
  21. cmGeneratorTarget* gt
  22. )
  23. : WorkingDirectory(wd)
  24. , GeneratorTarget(gt)
  25. , Target(gt->Target)
  26. , Makefile(gt->Makefile)
  27. , LocalGenerator(static_cast<cmLocalCommonGenerator*>(gt->LocalGenerator))
  28. , GlobalGenerator(static_cast<cmGlobalCommonGenerator*>(
  29. gt->LocalGenerator->GetGlobalGenerator()))
  30. , ConfigName(LocalGenerator->GetConfigName())
  31. , ModuleDefinitionFile(GeneratorTarget->GetModuleDefinitionFile(ConfigName))
  32. , FortranModuleDirectoryComputed(false)
  33. {
  34. }
  35. cmCommonTargetGenerator::~cmCommonTargetGenerator()
  36. {
  37. }
  38. std::string const& cmCommonTargetGenerator::GetConfigName() const
  39. {
  40. return this->ConfigName;
  41. }
  42. std::string cmCommonTargetGenerator::Convert(
  43. std::string const& source,
  44. cmLocalGenerator::RelativeRoot relative,
  45. cmLocalGenerator::OutputFormat output)
  46. {
  47. return this->LocalGenerator->Convert(source, relative, output);
  48. }
  49. //----------------------------------------------------------------------------
  50. const char* cmCommonTargetGenerator::GetFeature(const std::string& feature)
  51. {
  52. return this->GeneratorTarget->GetFeature(feature, this->ConfigName);
  53. }
  54. //----------------------------------------------------------------------------
  55. bool cmCommonTargetGenerator::GetFeatureAsBool(const std::string& feature)
  56. {
  57. return this->GeneratorTarget->GetFeatureAsBool(feature, this->ConfigName);
  58. }
  59. //----------------------------------------------------------------------------
  60. void cmCommonTargetGenerator::AddFeatureFlags(
  61. std::string& flags, const std::string& lang
  62. )
  63. {
  64. // Add language-specific flags.
  65. this->LocalGenerator->AddLanguageFlags(flags, lang, this->ConfigName);
  66. if(this->GetFeatureAsBool("INTERPROCEDURAL_OPTIMIZATION"))
  67. {
  68. this->LocalGenerator->AppendFeatureOptions(flags, lang, "IPO");
  69. }
  70. }
  71. //----------------------------------------------------------------------------
  72. void cmCommonTargetGenerator::AddModuleDefinitionFlag(std::string& flags)
  73. {
  74. if(this->ModuleDefinitionFile.empty())
  75. {
  76. return;
  77. }
  78. // TODO: Create a per-language flag variable.
  79. const char* defFileFlag =
  80. this->Makefile->GetDefinition("CMAKE_LINK_DEF_FILE_FLAG");
  81. if(!defFileFlag)
  82. {
  83. return;
  84. }
  85. // Append the flag and value. Use ConvertToLinkReference to help
  86. // vs6's "cl -link" pass it to the linker.
  87. std::string flag = defFileFlag;
  88. flag += (this->LocalGenerator->ConvertToLinkReference(
  89. this->ModuleDefinitionFile));
  90. this->LocalGenerator->AppendFlags(flags, flag);
  91. }
  92. //----------------------------------------------------------------------------
  93. std::string cmCommonTargetGenerator::ComputeFortranModuleDirectory() const
  94. {
  95. std::string mod_dir;
  96. const char* target_mod_dir =
  97. this->Target->GetProperty("Fortran_MODULE_DIRECTORY");
  98. const char* moddir_flag =
  99. this->Makefile->GetDefinition("CMAKE_Fortran_MODDIR_FLAG");
  100. if(target_mod_dir && moddir_flag)
  101. {
  102. // Compute the full path to the module directory.
  103. if(cmSystemTools::FileIsFullPath(target_mod_dir))
  104. {
  105. // Already a full path.
  106. mod_dir = target_mod_dir;
  107. }
  108. else
  109. {
  110. // Interpret relative to the current output directory.
  111. mod_dir = this->Makefile->GetCurrentBinaryDirectory();
  112. mod_dir += "/";
  113. mod_dir += target_mod_dir;
  114. }
  115. // Make sure the module output directory exists.
  116. cmSystemTools::MakeDirectory(mod_dir);
  117. }
  118. return mod_dir;
  119. }
  120. //----------------------------------------------------------------------------
  121. std::string cmCommonTargetGenerator::GetFortranModuleDirectory()
  122. {
  123. // Compute the module directory.
  124. if(!this->FortranModuleDirectoryComputed)
  125. {
  126. this->FortranModuleDirectoryComputed = true;
  127. this->FortranModuleDirectory = this->ComputeFortranModuleDirectory();
  128. }
  129. // Return the computed directory.
  130. return this->FortranModuleDirectory;
  131. }
  132. //----------------------------------------------------------------------------
  133. void cmCommonTargetGenerator::AddFortranFlags(std::string& flags)
  134. {
  135. // Enable module output if necessary.
  136. if(const char* modout_flag =
  137. this->Makefile->GetDefinition("CMAKE_Fortran_MODOUT_FLAG"))
  138. {
  139. this->LocalGenerator->AppendFlags(flags, modout_flag);
  140. }
  141. // Add a module output directory flag if necessary.
  142. std::string mod_dir = this->GetFortranModuleDirectory();
  143. if (!mod_dir.empty())
  144. {
  145. mod_dir = this->Convert(mod_dir,
  146. this->WorkingDirectory,
  147. cmLocalGenerator::SHELL);
  148. }
  149. else
  150. {
  151. mod_dir =
  152. this->Makefile->GetSafeDefinition("CMAKE_Fortran_MODDIR_DEFAULT");
  153. }
  154. if (!mod_dir.empty())
  155. {
  156. const char* moddir_flag =
  157. this->Makefile->GetRequiredDefinition("CMAKE_Fortran_MODDIR_FLAG");
  158. std::string modflag = moddir_flag;
  159. modflag += mod_dir;
  160. this->LocalGenerator->AppendFlags(flags, modflag);
  161. }
  162. // If there is a separate module path flag then duplicate the
  163. // include path with it. This compiler does not search the include
  164. // path for modules.
  165. if(const char* modpath_flag =
  166. this->Makefile->GetDefinition("CMAKE_Fortran_MODPATH_FLAG"))
  167. {
  168. std::vector<std::string> includes;
  169. const std::string& config =
  170. this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
  171. this->LocalGenerator->GetIncludeDirectories(includes,
  172. this->GeneratorTarget,
  173. "C", config);
  174. for(std::vector<std::string>::const_iterator idi = includes.begin();
  175. idi != includes.end(); ++idi)
  176. {
  177. std::string flg = modpath_flag;
  178. flg += this->Convert(*idi,
  179. cmLocalGenerator::NONE,
  180. cmLocalGenerator::SHELL);
  181. this->LocalGenerator->AppendFlags(flags, flg);
  182. }
  183. }
  184. }
  185. //----------------------------------------------------------------------------
  186. void
  187. cmCommonTargetGenerator
  188. ::AppendFortranFormatFlags(std::string& flags, cmSourceFile const& source)
  189. {
  190. const char* srcfmt = source.GetProperty("Fortran_FORMAT");
  191. cmLocalGenerator::FortranFormat format =
  192. this->LocalGenerator->GetFortranFormat(srcfmt);
  193. if(format == cmLocalGenerator::FortranFormatNone)
  194. {
  195. const char* tgtfmt = this->Target->GetProperty("Fortran_FORMAT");
  196. format = this->LocalGenerator->GetFortranFormat(tgtfmt);
  197. }
  198. const char* var = 0;
  199. switch (format)
  200. {
  201. case cmLocalGenerator::FortranFormatFixed:
  202. var = "CMAKE_Fortran_FORMAT_FIXED_FLAG"; break;
  203. case cmLocalGenerator::FortranFormatFree:
  204. var = "CMAKE_Fortran_FORMAT_FREE_FLAG"; break;
  205. default: break;
  206. }
  207. if(var)
  208. {
  209. this->LocalGenerator->AppendFlags(
  210. flags, this->Makefile->GetDefinition(var));
  211. }
  212. }
  213. //----------------------------------------------------------------------------
  214. std::string cmCommonTargetGenerator::GetFrameworkFlags(std::string const& l)
  215. {
  216. if(!this->Makefile->IsOn("APPLE"))
  217. {
  218. return std::string();
  219. }
  220. std::string fwSearchFlagVar = "CMAKE_" + l + "_FRAMEWORK_SEARCH_FLAG";
  221. const char* fwSearchFlag =
  222. this->Makefile->GetDefinition(fwSearchFlagVar);
  223. if(!(fwSearchFlag && *fwSearchFlag))
  224. {
  225. return std::string();
  226. }
  227. std::set<std::string> emitted;
  228. #ifdef __APPLE__ /* don't insert this when crosscompiling e.g. to iphone */
  229. emitted.insert("/System/Library/Frameworks");
  230. #endif
  231. std::vector<std::string> includes;
  232. const std::string& config =
  233. this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
  234. this->LocalGenerator->GetIncludeDirectories(includes,
  235. this->GeneratorTarget,
  236. "C", config);
  237. // check all include directories for frameworks as this
  238. // will already have added a -F for the framework
  239. for(std::vector<std::string>::iterator i = includes.begin();
  240. i != includes.end(); ++i)
  241. {
  242. if(this->Target->NameResolvesToFramework(*i))
  243. {
  244. std::string frameworkDir = *i;
  245. frameworkDir += "/../";
  246. frameworkDir = cmSystemTools::CollapseFullPath(frameworkDir);
  247. emitted.insert(frameworkDir);
  248. }
  249. }
  250. std::string flags;
  251. const char* cfg = this->LocalGenerator->GetConfigName().c_str();
  252. if(cmComputeLinkInformation* cli =
  253. this->GeneratorTarget->GetLinkInformation(cfg))
  254. {
  255. std::vector<std::string> const& frameworks = cli->GetFrameworkPaths();
  256. for(std::vector<std::string>::const_iterator i = frameworks.begin();
  257. i != frameworks.end(); ++i)
  258. {
  259. if(emitted.insert(*i).second)
  260. {
  261. flags += fwSearchFlag;
  262. flags += this->LocalGenerator
  263. ->ConvertToOutputFormat(*i, cmLocalGenerator::SHELL);
  264. flags += " ";
  265. }
  266. }
  267. }
  268. return flags;
  269. }
  270. //----------------------------------------------------------------------------
  271. std::string cmCommonTargetGenerator::GetFlags(const std::string &l)
  272. {
  273. ByLanguageMap::iterator i = this->FlagsByLanguage.find(l);
  274. if (i == this->FlagsByLanguage.end())
  275. {
  276. std::string flags;
  277. const char *lang = l.c_str();
  278. // Add language feature flags.
  279. this->AddFeatureFlags(flags, lang);
  280. this->LocalGenerator->AddArchitectureFlags(flags, this->GeneratorTarget,
  281. lang, this->ConfigName);
  282. // Fortran-specific flags computed for this target.
  283. if(l == "Fortran")
  284. {
  285. this->AddFortranFlags(flags);
  286. }
  287. this->LocalGenerator->AddCMP0018Flags(flags, this->Target,
  288. lang, this->ConfigName);
  289. this->LocalGenerator->AddVisibilityPresetFlags(flags, this->Target,
  290. lang);
  291. // Append old-style preprocessor definition flags.
  292. this->LocalGenerator->
  293. AppendFlags(flags, this->Makefile->GetDefineFlags());
  294. // Add framework directory flags.
  295. this->LocalGenerator->
  296. AppendFlags(flags,this->GetFrameworkFlags(l));
  297. // Add target-specific flags.
  298. this->LocalGenerator->AddCompileOptions(flags, this->Target,
  299. lang, this->ConfigName);
  300. ByLanguageMap::value_type entry(l, flags);
  301. i = this->FlagsByLanguage.insert(entry).first;
  302. }
  303. return i->second;
  304. }
  305. std::string cmCommonTargetGenerator::GetDefines(const std::string &l)
  306. {
  307. ByLanguageMap::iterator i = this->DefinesByLanguage.find(l);
  308. if (i == this->DefinesByLanguage.end())
  309. {
  310. std::set<std::string> defines;
  311. const char *lang = l.c_str();
  312. // Add the export symbol definition for shared library objects.
  313. if(const char* exportMacro = this->Target->GetExportMacro())
  314. {
  315. this->LocalGenerator->AppendDefines(defines, exportMacro);
  316. }
  317. // Add preprocessor definitions for this target and configuration.
  318. this->LocalGenerator->AddCompileDefinitions(defines, this->Target,
  319. this->LocalGenerator->GetConfigName(), l);
  320. std::string definesString;
  321. this->LocalGenerator->JoinDefines(defines, definesString, lang);
  322. ByLanguageMap::value_type entry(l, definesString);
  323. i = this->DefinesByLanguage.insert(entry).first;
  324. }
  325. return i->second;
  326. }
  327. std::string cmCommonTargetGenerator::GetIncludes(std::string const& l)
  328. {
  329. ByLanguageMap::iterator i = this->IncludesByLanguage.find(l);
  330. if (i == this->IncludesByLanguage.end())
  331. {
  332. std::string includes;
  333. this->AddIncludeFlags(includes, l);
  334. ByLanguageMap::value_type entry(l, includes);
  335. i = this->IncludesByLanguage.insert(entry).first;
  336. }
  337. return i->second;
  338. }
  339. std::vector<std::string>
  340. cmCommonTargetGenerator::GetLinkedTargetDirectories() const
  341. {
  342. std::vector<std::string> dirs;
  343. std::set<cmGeneratorTarget const*> emitted;
  344. if (cmComputeLinkInformation* cli =
  345. this->GeneratorTarget->GetLinkInformation(this->ConfigName))
  346. {
  347. cmComputeLinkInformation::ItemVector const& items = cli->GetItems();
  348. for(cmComputeLinkInformation::ItemVector::const_iterator
  349. i = items.begin(); i != items.end(); ++i)
  350. {
  351. cmGeneratorTarget const* linkee = i->Target;
  352. if(linkee && !linkee->IsImported()
  353. // We can ignore the INTERFACE_LIBRARY items because
  354. // Target->GetLinkInformation already processed their
  355. // link interface and they don't have any output themselves.
  356. && linkee->GetType() != cmState::INTERFACE_LIBRARY
  357. && emitted.insert(linkee).second)
  358. {
  359. cmLocalGenerator* lg = linkee->GetLocalGenerator();
  360. std::string di = lg->GetCurrentBinaryDirectory();
  361. di += "/";
  362. di += lg->GetTargetDirectory(linkee);
  363. dirs.push_back(di);
  364. }
  365. }
  366. }
  367. return dirs;
  368. }
  369. std::string cmCommonTargetGenerator::GetManifests()
  370. {
  371. std::vector<cmSourceFile const*> manifest_srcs;
  372. this->GeneratorTarget->GetManifests(manifest_srcs, this->ConfigName);
  373. std::vector<std::string> manifests;
  374. for (std::vector<cmSourceFile const*>::iterator mi = manifest_srcs.begin();
  375. mi != manifest_srcs.end(); ++mi)
  376. {
  377. manifests.push_back(this->Convert((*mi)->GetFullPath(),
  378. this->WorkingDirectory,
  379. cmOutputConverter::SHELL));
  380. }
  381. return cmJoin(manifests, " ");
  382. }