cmCommonTargetGenerator.cxx 14 KB

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