cmCommonTargetGenerator.cxx 14 KB

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