cmGlobalVisualStudio10Generator.cxx 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file Copyright.txt or https://cmake.org/licensing for details. */
  3. #include "cmGlobalVisualStudio10Generator.h"
  4. #include "cmAlgorithms.h"
  5. #include "cmDocumentationEntry.h"
  6. #include "cmGeneratorTarget.h"
  7. #include "cmLocalVisualStudio10Generator.h"
  8. #include "cmMakefile.h"
  9. #include "cmSourceFile.h"
  10. #include "cmVS10CLFlagTable.h"
  11. #include "cmVS10CSharpFlagTable.h"
  12. #include "cmVS10LibFlagTable.h"
  13. #include "cmVS10LinkFlagTable.h"
  14. #include "cmVS10MASMFlagTable.h"
  15. #include "cmVS10NASMFlagTable.h"
  16. #include "cmVS10RCFlagTable.h"
  17. #include "cmVersion.h"
  18. #include "cmVisualStudioSlnData.h"
  19. #include "cmVisualStudioSlnParser.h"
  20. #include "cmXMLWriter.h"
  21. #include "cmake.h"
  22. #include <cmsys/FStream.hxx>
  23. #include <cmsys/Glob.hxx>
  24. #include <cmsys/RegularExpression.hxx>
  25. #include <algorithm>
  26. static const char vs10generatorName[] = "Visual Studio 10 2010";
  27. // Map generator name without year to name with year.
  28. static const char* cmVS10GenName(const std::string& name, std::string& genName)
  29. {
  30. if (strncmp(name.c_str(), vs10generatorName,
  31. sizeof(vs10generatorName) - 6) != 0) {
  32. return 0;
  33. }
  34. const char* p = name.c_str() + sizeof(vs10generatorName) - 6;
  35. if (cmHasLiteralPrefix(p, " 2010")) {
  36. p += 5;
  37. }
  38. genName = std::string(vs10generatorName) + p;
  39. return p;
  40. }
  41. class cmGlobalVisualStudio10Generator::Factory
  42. : public cmGlobalGeneratorFactory
  43. {
  44. public:
  45. cmGlobalGenerator* CreateGlobalGenerator(const std::string& name,
  46. cmake* cm) const CM_OVERRIDE
  47. {
  48. std::string genName;
  49. const char* p = cmVS10GenName(name, genName);
  50. if (!p) {
  51. return 0;
  52. }
  53. if (!*p) {
  54. return new cmGlobalVisualStudio10Generator(cm, genName, "");
  55. }
  56. if (*p++ != ' ') {
  57. return 0;
  58. }
  59. if (strcmp(p, "Win64") == 0) {
  60. return new cmGlobalVisualStudio10Generator(cm, genName, "x64");
  61. }
  62. if (strcmp(p, "IA64") == 0) {
  63. return new cmGlobalVisualStudio10Generator(cm, genName, "Itanium");
  64. }
  65. return 0;
  66. }
  67. void GetDocumentation(cmDocumentationEntry& entry) const CM_OVERRIDE
  68. {
  69. entry.Name = std::string(vs10generatorName) + " [arch]";
  70. entry.Brief = "Generates Visual Studio 2010 project files. "
  71. "Optional [arch] can be \"Win64\" or \"IA64\".";
  72. }
  73. void GetGenerators(std::vector<std::string>& names) const CM_OVERRIDE
  74. {
  75. names.push_back(vs10generatorName);
  76. names.push_back(vs10generatorName + std::string(" IA64"));
  77. names.push_back(vs10generatorName + std::string(" Win64"));
  78. }
  79. bool SupportsToolset() const CM_OVERRIDE { return true; }
  80. bool SupportsPlatform() const CM_OVERRIDE { return true; }
  81. };
  82. cmGlobalGeneratorFactory* cmGlobalVisualStudio10Generator::NewFactory()
  83. {
  84. return new Factory;
  85. }
  86. cmGlobalVisualStudio10Generator::cmGlobalVisualStudio10Generator(
  87. cmake* cm, const std::string& name, const std::string& platformName)
  88. : cmGlobalVisualStudio8Generator(cm, name, platformName)
  89. {
  90. std::string vc10Express;
  91. this->ExpressEdition = cmSystemTools::ReadRegistryValue(
  92. "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\10.0\\Setup\\VC;"
  93. "ProductDir",
  94. vc10Express, cmSystemTools::KeyWOW64_32);
  95. this->CudaEnabled = false;
  96. this->SystemIsWindowsCE = false;
  97. this->SystemIsWindowsPhone = false;
  98. this->SystemIsWindowsStore = false;
  99. this->MSBuildCommandInitialized = false;
  100. {
  101. std::string envPlatformToolset;
  102. if (cmSystemTools::GetEnv("PlatformToolset", envPlatformToolset) &&
  103. envPlatformToolset == "Windows7.1SDK") {
  104. // We are running from a Windows7.1SDK command prompt.
  105. this->DefaultPlatformToolset = "Windows7.1SDK";
  106. } else {
  107. this->DefaultPlatformToolset = "v100";
  108. }
  109. }
  110. this->DefaultClFlagTable = cmVS10CLFlagTable;
  111. this->DefaultCSharpFlagTable = cmVS10CSharpFlagTable;
  112. this->DefaultLibFlagTable = cmVS10LibFlagTable;
  113. this->DefaultLinkFlagTable = cmVS10LinkFlagTable;
  114. this->DefaultMasmFlagTable = cmVS10MASMFlagTable;
  115. this->DefaultNasmFlagTable = cmVS10NASMFlagTable;
  116. this->DefaultRcFlagTable = cmVS10RCFlagTable;
  117. this->Version = VS10;
  118. }
  119. bool cmGlobalVisualStudio10Generator::MatchesGeneratorName(
  120. const std::string& name) const
  121. {
  122. std::string genName;
  123. if (cmVS10GenName(name, genName)) {
  124. return genName == this->GetName();
  125. }
  126. return false;
  127. }
  128. bool cmGlobalVisualStudio10Generator::SetSystemName(std::string const& s,
  129. cmMakefile* mf)
  130. {
  131. this->SystemName = s;
  132. this->SystemVersion = mf->GetSafeDefinition("CMAKE_SYSTEM_VERSION");
  133. if (!this->InitializeSystem(mf)) {
  134. return false;
  135. }
  136. return this->cmGlobalVisualStudio8Generator::SetSystemName(s, mf);
  137. }
  138. bool cmGlobalVisualStudio10Generator::SetGeneratorPlatform(
  139. std::string const& p, cmMakefile* mf)
  140. {
  141. if (!this->cmGlobalVisualStudio8Generator::SetGeneratorPlatform(p, mf)) {
  142. return false;
  143. }
  144. if (this->GetPlatformName() == "Itanium" ||
  145. this->GetPlatformName() == "x64") {
  146. if (this->IsExpressEdition() && !this->Find64BitTools(mf)) {
  147. return false;
  148. }
  149. }
  150. return true;
  151. }
  152. static void cmCudaToolVersion(std::string& s)
  153. {
  154. // "CUDA x.y.props" => "x.y"
  155. s = s.substr(5);
  156. s = s.substr(0, s.size() - 6);
  157. }
  158. bool cmGlobalVisualStudio10Generator::SetGeneratorToolset(
  159. std::string const& ts, cmMakefile* mf)
  160. {
  161. if (this->SystemIsWindowsCE && ts.empty() &&
  162. this->DefaultPlatformToolset.empty()) {
  163. std::ostringstream e;
  164. e << this->GetName() << " Windows CE version '" << this->SystemVersion
  165. << "' requires CMAKE_GENERATOR_TOOLSET to be set.";
  166. mf->IssueMessage(cmake::FATAL_ERROR, e.str());
  167. return false;
  168. }
  169. if (!this->ParseGeneratorToolset(ts, mf)) {
  170. return false;
  171. }
  172. if (!this->FindVCTargetsPath(mf)) {
  173. return false;
  174. }
  175. if (this->GeneratorToolsetCuda.empty()) {
  176. // Find the highest available version of the CUDA tools.
  177. std::vector<std::string> cudaTools;
  178. std::string const bcDir = this->VCTargetsPath + "/BuildCustomizations";
  179. cmsys::Glob gl;
  180. gl.SetRelative(bcDir.c_str());
  181. if (gl.FindFiles(bcDir + "/CUDA *.props")) {
  182. cudaTools = gl.GetFiles();
  183. }
  184. if (!cudaTools.empty()) {
  185. std::for_each(cudaTools.begin(), cudaTools.end(), cmCudaToolVersion);
  186. std::sort(cudaTools.begin(), cudaTools.end(),
  187. cmSystemTools::VersionCompareGreater);
  188. this->GeneratorToolsetCuda = cudaTools.at(0);
  189. }
  190. }
  191. if (const char* toolset = this->GetPlatformToolset()) {
  192. mf->AddDefinition("CMAKE_VS_PLATFORM_TOOLSET", toolset);
  193. }
  194. if (const char* hostArch = this->GetPlatformToolsetHostArchitecture()) {
  195. mf->AddDefinition("CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE", hostArch);
  196. }
  197. if (const char* cuda = this->GetPlatformToolsetCuda()) {
  198. mf->AddDefinition("CMAKE_VS_PLATFORM_TOOLSET_CUDA", cuda);
  199. }
  200. return true;
  201. }
  202. bool cmGlobalVisualStudio10Generator::ParseGeneratorToolset(
  203. std::string const& ts, cmMakefile* mf)
  204. {
  205. std::vector<std::string> const fields = cmSystemTools::tokenize(ts, ",");
  206. std::vector<std::string>::const_iterator fi = fields.begin();
  207. if (fi == fields.end()) {
  208. return true;
  209. }
  210. // The first field may be the VS platform toolset.
  211. if (fi->find('=') == fi->npos) {
  212. this->GeneratorToolset = *fi;
  213. ++fi;
  214. }
  215. std::set<std::string> handled;
  216. // The rest of the fields must be key=value pairs.
  217. for (; fi != fields.end(); ++fi) {
  218. std::string::size_type pos = fi->find('=');
  219. if (pos == fi->npos) {
  220. std::ostringstream e;
  221. /* clang-format off */
  222. e <<
  223. "Generator\n"
  224. " " << this->GetName() << "\n"
  225. "given toolset specification\n"
  226. " " << ts << "\n"
  227. "that contains a field after the first ',' with no '='."
  228. ;
  229. /* clang-format on */
  230. mf->IssueMessage(cmake::FATAL_ERROR, e.str());
  231. return false;
  232. }
  233. std::string const key = fi->substr(0, pos);
  234. std::string const value = fi->substr(pos + 1);
  235. if (!handled.insert(key).second) {
  236. std::ostringstream e;
  237. /* clang-format off */
  238. e <<
  239. "Generator\n"
  240. " " << this->GetName() << "\n"
  241. "given toolset specification\n"
  242. " " << ts << "\n"
  243. "that contains duplicate field key '" << key << "'."
  244. ;
  245. /* clang-format on */
  246. mf->IssueMessage(cmake::FATAL_ERROR, e.str());
  247. return false;
  248. }
  249. if (!this->ProcessGeneratorToolsetField(key, value)) {
  250. std::ostringstream e;
  251. /* clang-format off */
  252. e <<
  253. "Generator\n"
  254. " " << this->GetName() << "\n"
  255. "given toolset specification\n"
  256. " " << ts << "\n"
  257. "that contains invalid field '" << *fi << "'."
  258. ;
  259. /* clang-format on */
  260. mf->IssueMessage(cmake::FATAL_ERROR, e.str());
  261. return false;
  262. }
  263. }
  264. return true;
  265. }
  266. bool cmGlobalVisualStudio10Generator::ProcessGeneratorToolsetField(
  267. std::string const& key, std::string const& value)
  268. {
  269. if (key == "cuda") {
  270. this->GeneratorToolsetCuda = value;
  271. return true;
  272. }
  273. return false;
  274. }
  275. bool cmGlobalVisualStudio10Generator::InitializeSystem(cmMakefile* mf)
  276. {
  277. if (this->SystemName == "Windows") {
  278. if (!this->InitializeWindows(mf)) {
  279. return false;
  280. }
  281. } else if (this->SystemName == "WindowsCE") {
  282. this->SystemIsWindowsCE = true;
  283. if (!this->InitializeWindowsCE(mf)) {
  284. return false;
  285. }
  286. } else if (this->SystemName == "WindowsPhone") {
  287. this->SystemIsWindowsPhone = true;
  288. if (!this->InitializeWindowsPhone(mf)) {
  289. return false;
  290. }
  291. } else if (this->SystemName == "WindowsStore") {
  292. this->SystemIsWindowsStore = true;
  293. if (!this->InitializeWindowsStore(mf)) {
  294. return false;
  295. }
  296. } else if (this->SystemName == "Android") {
  297. if (this->DefaultPlatformName != "Win32") {
  298. std::ostringstream e;
  299. e << "CMAKE_SYSTEM_NAME is 'Android' but CMAKE_GENERATOR "
  300. << "specifies a platform too: '" << this->GetName() << "'";
  301. mf->IssueMessage(cmake::FATAL_ERROR, e.str());
  302. return false;
  303. }
  304. std::string v = this->GetInstalledNsightTegraVersion();
  305. if (v.empty()) {
  306. mf->IssueMessage(cmake::FATAL_ERROR,
  307. "CMAKE_SYSTEM_NAME is 'Android' but "
  308. "'NVIDIA Nsight Tegra Visual Studio Edition' "
  309. "is not installed.");
  310. return false;
  311. }
  312. this->DefaultPlatformName = "Tegra-Android";
  313. this->DefaultPlatformToolset = "Default";
  314. this->NsightTegraVersion = v;
  315. mf->AddDefinition("CMAKE_VS_NsightTegra_VERSION", v.c_str());
  316. }
  317. return true;
  318. }
  319. bool cmGlobalVisualStudio10Generator::InitializeWindows(cmMakefile*)
  320. {
  321. return true;
  322. }
  323. bool cmGlobalVisualStudio10Generator::InitializeWindowsCE(cmMakefile* mf)
  324. {
  325. if (this->DefaultPlatformName != "Win32") {
  326. std::ostringstream e;
  327. e << "CMAKE_SYSTEM_NAME is 'WindowsCE' but CMAKE_GENERATOR "
  328. << "specifies a platform too: '" << this->GetName() << "'";
  329. mf->IssueMessage(cmake::FATAL_ERROR, e.str());
  330. return false;
  331. }
  332. this->DefaultPlatformToolset = this->SelectWindowsCEToolset();
  333. return true;
  334. }
  335. bool cmGlobalVisualStudio10Generator::InitializeWindowsPhone(cmMakefile* mf)
  336. {
  337. std::ostringstream e;
  338. e << this->GetName() << " does not support Windows Phone.";
  339. mf->IssueMessage(cmake::FATAL_ERROR, e.str());
  340. return false;
  341. }
  342. bool cmGlobalVisualStudio10Generator::InitializeWindowsStore(cmMakefile* mf)
  343. {
  344. std::ostringstream e;
  345. e << this->GetName() << " does not support Windows Store.";
  346. mf->IssueMessage(cmake::FATAL_ERROR, e.str());
  347. return false;
  348. }
  349. bool cmGlobalVisualStudio10Generator::SelectWindowsPhoneToolset(
  350. std::string& toolset) const
  351. {
  352. toolset = "";
  353. return false;
  354. }
  355. bool cmGlobalVisualStudio10Generator::SelectWindowsStoreToolset(
  356. std::string& toolset) const
  357. {
  358. toolset = "";
  359. return false;
  360. }
  361. std::string cmGlobalVisualStudio10Generator::SelectWindowsCEToolset() const
  362. {
  363. if (this->SystemVersion == "8.0") {
  364. return "CE800";
  365. }
  366. return "";
  367. }
  368. void cmGlobalVisualStudio10Generator::WriteSLNHeader(std::ostream& fout)
  369. {
  370. fout << "Microsoft Visual Studio Solution File, Format Version 11.00\n";
  371. if (this->ExpressEdition) {
  372. fout << "# Visual C++ Express 2010\n";
  373. } else {
  374. fout << "# Visual Studio 2010\n";
  375. }
  376. }
  377. ///! Create a local generator appropriate to this Global Generator
  378. cmLocalGenerator* cmGlobalVisualStudio10Generator::CreateLocalGenerator(
  379. cmMakefile* mf)
  380. {
  381. return new cmLocalVisualStudio10Generator(this, mf);
  382. }
  383. void cmGlobalVisualStudio10Generator::Generate()
  384. {
  385. this->LongestSource = LongestSourcePath();
  386. this->cmGlobalVisualStudio8Generator::Generate();
  387. if (this->LongestSource.Length > 0) {
  388. cmLocalGenerator* lg = this->LongestSource.Target->GetLocalGenerator();
  389. std::ostringstream e;
  390. /* clang-format off */
  391. e <<
  392. "The binary and/or source directory paths may be too long to generate "
  393. "Visual Studio 10 files for this project. "
  394. "Consider choosing shorter directory names to build this project with "
  395. "Visual Studio 10. "
  396. "A more detailed explanation follows."
  397. "\n"
  398. "There is a bug in the VS 10 IDE that renders property dialog fields "
  399. "blank for files referenced by full path in the project file. "
  400. "However, CMake must reference at least one file by full path:\n"
  401. " " << this->LongestSource.SourceFile->GetFullPath() << "\n"
  402. "This is because some Visual Studio tools would append the relative "
  403. "path to the end of the referencing directory path, as in:\n"
  404. " " << lg->GetCurrentBinaryDirectory() << "/"
  405. << this->LongestSource.SourceRel << "\n"
  406. "and then incorrectly complain that the file does not exist because "
  407. "the path length is too long for some internal buffer or API. "
  408. "To avoid this problem CMake must use a full path for this file "
  409. "which then triggers the VS 10 property dialog bug.";
  410. /* clang-format on */
  411. lg->IssueMessage(cmake::WARNING, e.str().c_str());
  412. }
  413. }
  414. void cmGlobalVisualStudio10Generator::EnableLanguage(
  415. std::vector<std::string> const& lang, cmMakefile* mf, bool optional)
  416. {
  417. for (std::vector<std::string>::const_iterator it = lang.begin();
  418. it != lang.end(); ++it) {
  419. if (*it == "ASM_NASM") {
  420. this->NasmEnabled = true;
  421. }
  422. if (*it == "CUDA") {
  423. this->CudaEnabled = true;
  424. }
  425. }
  426. this->AddPlatformDefinitions(mf);
  427. cmGlobalVisualStudio8Generator::EnableLanguage(lang, mf, optional);
  428. }
  429. const char* cmGlobalVisualStudio10Generator::GetPlatformToolset() const
  430. {
  431. std::string const& toolset = this->GetPlatformToolsetString();
  432. if (toolset.empty()) {
  433. return CM_NULLPTR;
  434. }
  435. return toolset.c_str();
  436. }
  437. std::string const& cmGlobalVisualStudio10Generator::GetPlatformToolsetString()
  438. const
  439. {
  440. if (!this->GeneratorToolset.empty()) {
  441. return this->GeneratorToolset;
  442. }
  443. if (!this->DefaultPlatformToolset.empty()) {
  444. return this->DefaultPlatformToolset;
  445. }
  446. static std::string const empty;
  447. return empty;
  448. }
  449. const char*
  450. cmGlobalVisualStudio10Generator::GetPlatformToolsetHostArchitecture() const
  451. {
  452. if (!this->GeneratorToolsetHostArchitecture.empty()) {
  453. return this->GeneratorToolsetHostArchitecture.c_str();
  454. }
  455. return CM_NULLPTR;
  456. }
  457. const char* cmGlobalVisualStudio10Generator::GetPlatformToolsetCuda() const
  458. {
  459. if (!this->GeneratorToolsetCuda.empty()) {
  460. return this->GeneratorToolsetCuda.c_str();
  461. }
  462. return CM_NULLPTR;
  463. }
  464. std::string const&
  465. cmGlobalVisualStudio10Generator::GetPlatformToolsetCudaString() const
  466. {
  467. return this->GeneratorToolsetCuda;
  468. }
  469. bool cmGlobalVisualStudio10Generator::FindMakeProgram(cmMakefile* mf)
  470. {
  471. if (!this->cmGlobalVisualStudio8Generator::FindMakeProgram(mf)) {
  472. return false;
  473. }
  474. mf->AddDefinition("CMAKE_VS_MSBUILD_COMMAND",
  475. this->GetMSBuildCommand().c_str());
  476. return true;
  477. }
  478. std::string const& cmGlobalVisualStudio10Generator::GetMSBuildCommand()
  479. {
  480. if (!this->MSBuildCommandInitialized) {
  481. this->MSBuildCommandInitialized = true;
  482. this->MSBuildCommand = this->FindMSBuildCommand();
  483. }
  484. return this->MSBuildCommand;
  485. }
  486. std::string cmGlobalVisualStudio10Generator::FindMSBuildCommand()
  487. {
  488. std::string msbuild;
  489. std::string mskey;
  490. // Search in standard location.
  491. mskey = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\MSBuild\\ToolsVersions\\";
  492. mskey += this->GetToolsVersion();
  493. mskey += ";MSBuildToolsPath";
  494. if (cmSystemTools::ReadRegistryValue(mskey.c_str(), msbuild,
  495. cmSystemTools::KeyWOW64_32)) {
  496. cmSystemTools::ConvertToUnixSlashes(msbuild);
  497. msbuild += "/MSBuild.exe";
  498. if (cmSystemTools::FileExists(msbuild, true)) {
  499. return msbuild;
  500. }
  501. }
  502. msbuild = "MSBuild.exe";
  503. return msbuild;
  504. }
  505. std::string cmGlobalVisualStudio10Generator::FindDevEnvCommand()
  506. {
  507. if (this->ExpressEdition) {
  508. // Visual Studio Express >= 10 do not have "devenv.com" or
  509. // "VCExpress.exe" that we can use to build reliably.
  510. // Tell the caller it needs to use MSBuild instead.
  511. return "";
  512. }
  513. // Skip over the cmGlobalVisualStudio8Generator implementation because
  514. // we expect a real devenv and do not want to look for VCExpress.
  515. return this->cmGlobalVisualStudio71Generator::FindDevEnvCommand();
  516. }
  517. bool cmGlobalVisualStudio10Generator::FindVCTargetsPath(cmMakefile* mf)
  518. {
  519. // Skip this in special cases within our own test suite.
  520. if (this->GetPlatformName() == "Test Platform" ||
  521. this->GetPlatformToolsetString() == "Test Toolset") {
  522. return true;
  523. }
  524. std::string wd;
  525. if (!this->ConfiguredFilesPath.empty()) {
  526. // In a try-compile we are given the outer CMakeFiles directory.
  527. wd = this->ConfiguredFilesPath;
  528. } else {
  529. wd = this->GetCMakeInstance()->GetHomeOutputDirectory();
  530. wd += cmake::GetCMakeFilesDirectory();
  531. }
  532. wd += "/";
  533. wd += cmVersion::GetCMakeVersion();
  534. // We record the result persistently in a file.
  535. std::string const txt = wd + "/VCTargetsPath.txt";
  536. // If we have a recorded result, use it.
  537. {
  538. cmsys::ifstream fin(txt.c_str());
  539. if (fin && cmSystemTools::GetLineFromStream(fin, this->VCTargetsPath) &&
  540. cmSystemTools::FileIsDirectory(this->VCTargetsPath)) {
  541. cmSystemTools::ConvertToUnixSlashes(this->VCTargetsPath);
  542. return true;
  543. }
  544. }
  545. // Prepare the work directory.
  546. if (!cmSystemTools::MakeDirectory(wd)) {
  547. std::string e = "Failed to make directory:\n " + wd;
  548. mf->IssueMessage(cmake::FATAL_ERROR, e.c_str());
  549. cmSystemTools::SetFatalErrorOccured();
  550. return false;
  551. }
  552. // Generate a project file for MSBuild to tell us the VCTargetsPath value.
  553. std::string const vcxproj = "VCTargetsPath.vcxproj";
  554. {
  555. std::string const vcxprojAbs = wd + "/" + vcxproj;
  556. cmsys::ofstream fout(vcxprojAbs.c_str());
  557. cmXMLWriter xw(fout);
  558. /* clang-format off */
  559. xw.StartDocument();
  560. xw.StartElement("Project");
  561. xw.Attribute("DefaultTargets", "Build");
  562. xw.Attribute("ToolsVersion", "4.0");
  563. xw.Attribute("xmlns",
  564. "http://schemas.microsoft.com/developer/msbuild/2003");
  565. if (this->IsNsightTegra()) {
  566. xw.StartElement("PropertyGroup");
  567. xw.Attribute("Label", "NsightTegraProject");
  568. xw.StartElement("NsightTegraProjectRevisionNumber");
  569. xw.Content("6");
  570. xw.EndElement(); // NsightTegraProjectRevisionNumber
  571. xw.EndElement(); // PropertyGroup
  572. }
  573. xw.StartElement("ItemGroup");
  574. xw.Attribute("Label", "ProjectConfigurations");
  575. xw.StartElement("ProjectConfiguration");
  576. xw.Attribute("Include", "Debug|" + this->GetPlatformName());
  577. xw.StartElement("Configuration");
  578. xw.Content("Debug");
  579. xw.EndElement(); // Configuration
  580. xw.StartElement("Platform");
  581. xw.Content(this->GetPlatformName());
  582. xw.EndElement(); // Platform
  583. xw.EndElement(); // ProjectConfiguration
  584. xw.EndElement(); // ItemGroup
  585. xw.StartElement("PropertyGroup");
  586. xw.Attribute("Label", "Globals");
  587. xw.StartElement("ProjectGUID");
  588. xw.Content("{F3FC6D86-508D-3FB1-96D2-995F08B142EC}");
  589. xw.EndElement(); // ProjectGUID
  590. xw.StartElement("Keyword");
  591. xw.Content("Win32Proj");
  592. xw.EndElement(); // Keyword
  593. xw.StartElement("Platform");
  594. xw.Content(this->GetPlatformName());
  595. xw.EndElement(); // Platform
  596. if (this->GetSystemName() == "WindowsPhone") {
  597. xw.StartElement("ApplicationType");
  598. xw.Content("Windows Phone");
  599. xw.EndElement(); // ApplicationType
  600. xw.StartElement("ApplicationTypeRevision");
  601. xw.Content(this->GetSystemVersion());
  602. xw.EndElement(); // ApplicationTypeRevision
  603. } else if (this->GetSystemName() == "WindowsStore") {
  604. xw.StartElement("ApplicationType");
  605. xw.Content("Windows Store");
  606. xw.EndElement(); // ApplicationType
  607. xw.StartElement("ApplicationTypeRevision");
  608. xw.Content(this->GetSystemVersion());
  609. xw.EndElement(); // ApplicationTypeRevision
  610. }
  611. if (!this->WindowsTargetPlatformVersion.empty()) {
  612. xw.StartElement("WindowsTargetPlatformVersion");
  613. xw.Content(this->WindowsTargetPlatformVersion);
  614. xw.EndElement(); // WindowsTargetPlatformVersion
  615. }
  616. if (this->GetPlatformName() == "ARM") {
  617. xw.StartElement("WindowsSDKDesktopARMSupport");
  618. xw.Content("true");
  619. xw.EndElement(); // WindowsSDKDesktopARMSupport
  620. }
  621. xw.EndElement(); // PropertyGroup
  622. xw.StartElement("Import");
  623. xw.Attribute("Project",
  624. "$(VCTargetsPath)\\Microsoft.Cpp.Default.props");
  625. xw.EndElement(); // Import
  626. if (!this->GeneratorToolsetHostArchitecture.empty()) {
  627. xw.StartElement("PropertyGroup");
  628. xw.StartElement("PreferredToolArchitecture");
  629. xw.Content(this->GeneratorToolsetHostArchitecture);
  630. xw.EndElement(); // PreferredToolArchitecture
  631. xw.EndElement(); // PropertyGroup
  632. }
  633. xw.StartElement("PropertyGroup");
  634. xw.Attribute("Label", "Configuration");
  635. xw.StartElement("ConfigurationType");
  636. if (this->IsNsightTegra()) {
  637. // Tegra-Android platform does not understand "Utility".
  638. xw.Content("StaticLibrary");
  639. } else {
  640. xw.Content("Utility");
  641. }
  642. xw.EndElement(); // ConfigurationType
  643. xw.StartElement("CharacterSet");
  644. xw.Content("MultiByte");
  645. xw.EndElement(); // CharacterSet
  646. if (this->IsNsightTegra()) {
  647. xw.StartElement("NdkToolchainVersion");
  648. xw.Content(this->GetPlatformToolsetString());
  649. xw.EndElement(); // NdkToolchainVersion
  650. } else {
  651. xw.StartElement("PlatformToolset");
  652. xw.Content(this->GetPlatformToolsetString());
  653. xw.EndElement(); // PlatformToolset
  654. }
  655. xw.EndElement(); // PropertyGroup
  656. xw.StartElement("Import");
  657. xw.Attribute("Project", "$(VCTargetsPath)\\Microsoft.Cpp.props");
  658. xw.EndElement(); // Import
  659. xw.StartElement("ItemDefinitionGroup");
  660. xw.StartElement("PostBuildEvent");
  661. xw.StartElement("Command");
  662. xw.Content("echo VCTargetsPath=$(VCTargetsPath)");
  663. xw.EndElement(); // Command
  664. xw.EndElement(); // PostBuildEvent
  665. xw.EndElement(); // ItemDefinitionGroup
  666. xw.StartElement("Import");
  667. xw.Attribute("Project",
  668. "$(VCTargetsPath)\\Microsoft.Cpp.targets");
  669. xw.EndElement(); // Import
  670. xw.EndElement(); // Project
  671. xw.EndDocument();
  672. /* clang-format on */
  673. }
  674. std::vector<std::string> cmd;
  675. cmd.push_back(this->GetMSBuildCommand());
  676. cmd.push_back(vcxproj);
  677. cmd.push_back(std::string("/p:VisualStudioVersion=") +
  678. this->GetIDEVersion());
  679. std::string out;
  680. int ret = 0;
  681. cmsys::RegularExpression regex("\n *VCTargetsPath=([^%\r\n]+)[\r\n]");
  682. if (!cmSystemTools::RunSingleCommand(cmd, &out, &out, &ret, wd.c_str(),
  683. cmSystemTools::OUTPUT_NONE) ||
  684. ret != 0 || !regex.find(out)) {
  685. cmSystemTools::ReplaceString(out, "\n", "\n ");
  686. std::ostringstream e;
  687. /* clang-format off */
  688. e <<
  689. "Failed to run MSBuild command:\n"
  690. " " << cmd[0] << "\n"
  691. "to get the value of VCTargetsPath:\n"
  692. " " << out << "\n"
  693. ;
  694. /* clang-format on */
  695. if (ret != 0) {
  696. e << "Exit code: " << ret << "\n";
  697. }
  698. mf->IssueMessage(cmake::FATAL_ERROR, e.str().c_str());
  699. cmSystemTools::SetFatalErrorOccured();
  700. return false;
  701. }
  702. this->VCTargetsPath = regex.match(1);
  703. cmSystemTools::ConvertToUnixSlashes(this->VCTargetsPath);
  704. {
  705. cmsys::ofstream fout(txt.c_str());
  706. fout << this->VCTargetsPath << "\n";
  707. }
  708. return true;
  709. }
  710. void cmGlobalVisualStudio10Generator::GenerateBuildCommand(
  711. std::vector<std::string>& makeCommand, const std::string& makeProgram,
  712. const std::string& projectName, const std::string& projectDir,
  713. const std::string& targetName, const std::string& config, bool fast,
  714. bool verbose, std::vector<std::string> const& makeOptions)
  715. {
  716. // Select the caller- or user-preferred make program, else MSBuild.
  717. std::string makeProgramSelected =
  718. this->SelectMakeProgram(makeProgram, this->GetMSBuildCommand());
  719. // Check if the caller explicitly requested a devenv tool.
  720. std::string makeProgramLower = makeProgramSelected;
  721. cmSystemTools::LowerCase(makeProgramLower);
  722. bool useDevEnv = (makeProgramLower.find("devenv") != std::string::npos ||
  723. makeProgramLower.find("vcexpress") != std::string::npos);
  724. // MSBuild is preferred (and required for VS Express), but if the .sln has
  725. // an Intel Fortran .vfproj then we have to use devenv. Parse it to find out.
  726. cmSlnData slnData;
  727. {
  728. std::string slnFile;
  729. if (!projectDir.empty()) {
  730. slnFile = projectDir;
  731. slnFile += "/";
  732. }
  733. slnFile += projectName;
  734. slnFile += ".sln";
  735. cmVisualStudioSlnParser parser;
  736. if (parser.ParseFile(slnFile, slnData,
  737. cmVisualStudioSlnParser::DataGroupProjects)) {
  738. std::vector<cmSlnProjectEntry> slnProjects = slnData.GetProjects();
  739. for (std::vector<cmSlnProjectEntry>::iterator i = slnProjects.begin();
  740. !useDevEnv && i != slnProjects.end(); ++i) {
  741. std::string proj = i->GetRelativePath();
  742. if (proj.size() > 7 && proj.substr(proj.size() - 7) == ".vfproj") {
  743. useDevEnv = true;
  744. }
  745. }
  746. }
  747. }
  748. if (useDevEnv) {
  749. // Use devenv to build solutions containing Intel Fortran projects.
  750. cmGlobalVisualStudio7Generator::GenerateBuildCommand(
  751. makeCommand, makeProgram, projectName, projectDir, targetName, config,
  752. fast, verbose, makeOptions);
  753. return;
  754. }
  755. makeCommand.push_back(makeProgramSelected);
  756. std::string realTarget = targetName;
  757. // msbuild.exe CxxOnly.sln /t:Build /p:Configuration=Debug /target:ALL_BUILD
  758. if (realTarget.empty()) {
  759. realTarget = "ALL_BUILD";
  760. }
  761. if (realTarget == "clean") {
  762. makeCommand.push_back(std::string(projectName) + ".sln");
  763. makeCommand.push_back("/t:Clean");
  764. } else {
  765. std::string targetProject(realTarget);
  766. targetProject += ".vcxproj";
  767. if (targetProject.find('/') == std::string::npos) {
  768. // it might be in a subdir
  769. if (cmSlnProjectEntry const* proj =
  770. slnData.GetProjectByName(realTarget)) {
  771. targetProject = proj->GetRelativePath();
  772. cmSystemTools::ConvertToUnixSlashes(targetProject);
  773. }
  774. }
  775. makeCommand.push_back(targetProject);
  776. }
  777. std::string configArg = "/p:Configuration=";
  778. if (!config.empty()) {
  779. configArg += config;
  780. } else {
  781. configArg += "Debug";
  782. }
  783. makeCommand.push_back(configArg);
  784. makeCommand.push_back(std::string("/p:VisualStudioVersion=") +
  785. this->GetIDEVersion());
  786. makeCommand.insert(makeCommand.end(), makeOptions.begin(),
  787. makeOptions.end());
  788. }
  789. bool cmGlobalVisualStudio10Generator::Find64BitTools(cmMakefile* mf)
  790. {
  791. if (this->DefaultPlatformToolset == "v100") {
  792. // The v100 64-bit toolset does not exist in the express edition.
  793. this->DefaultPlatformToolset.clear();
  794. }
  795. if (this->GetPlatformToolset()) {
  796. return true;
  797. }
  798. // This edition does not come with 64-bit tools. Look for them.
  799. //
  800. // TODO: Detect available tools? x64\v100 exists but does not work?
  801. // HKLM\\SOFTWARE\\Microsoft\\MSBuild\\ToolsVersions\\4.0;VCTargetsPath
  802. // c:/Program Files (x86)/MSBuild/Microsoft.Cpp/v4.0/Platforms/
  803. // {Itanium,Win32,x64}/PlatformToolsets/{v100,v90,Windows7.1SDK}
  804. std::string winSDK_7_1;
  805. if (cmSystemTools::ReadRegistryValue(
  806. "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\"
  807. "Windows\\v7.1;InstallationFolder",
  808. winSDK_7_1)) {
  809. std::ostringstream m;
  810. m << "Found Windows SDK v7.1: " << winSDK_7_1;
  811. mf->DisplayStatus(m.str().c_str(), -1);
  812. this->DefaultPlatformToolset = "Windows7.1SDK";
  813. return true;
  814. } else {
  815. std::ostringstream e;
  816. /* clang-format off */
  817. e << "Cannot enable 64-bit tools with Visual Studio 2010 Express.\n"
  818. << "Install the Microsoft Windows SDK v7.1 to get 64-bit tools:\n"
  819. << " http://msdn.microsoft.com/en-us/windows/bb980924.aspx";
  820. /* clang-format on */
  821. mf->IssueMessage(cmake::FATAL_ERROR, e.str().c_str());
  822. cmSystemTools::SetFatalErrorOccured();
  823. return false;
  824. }
  825. }
  826. std::string cmGlobalVisualStudio10Generator::GenerateRuleFile(
  827. std::string const& output) const
  828. {
  829. // The VS 10 generator needs to create the .rule files on disk.
  830. // Hide them away under the CMakeFiles directory.
  831. std::string ruleDir = this->GetCMakeInstance()->GetHomeOutputDirectory();
  832. ruleDir += cmake::GetCMakeFilesDirectory();
  833. ruleDir += "/";
  834. ruleDir += cmSystemTools::ComputeStringMD5(
  835. cmSystemTools::GetFilenamePath(output).c_str());
  836. std::string ruleFile = ruleDir + "/";
  837. ruleFile += cmSystemTools::GetFilenameName(output);
  838. ruleFile += ".rule";
  839. return ruleFile;
  840. }
  841. void cmGlobalVisualStudio10Generator::PathTooLong(cmGeneratorTarget* target,
  842. cmSourceFile const* sf,
  843. std::string const& sfRel)
  844. {
  845. size_t len =
  846. (strlen(target->GetLocalGenerator()->GetCurrentBinaryDirectory()) + 1 +
  847. sfRel.length());
  848. if (len > this->LongestSource.Length) {
  849. this->LongestSource.Length = len;
  850. this->LongestSource.Target = target;
  851. this->LongestSource.SourceFile = sf;
  852. this->LongestSource.SourceRel = sfRel;
  853. }
  854. }
  855. bool cmGlobalVisualStudio10Generator::IsNsightTegra() const
  856. {
  857. return !this->NsightTegraVersion.empty();
  858. }
  859. std::string cmGlobalVisualStudio10Generator::GetNsightTegraVersion() const
  860. {
  861. return this->NsightTegraVersion;
  862. }
  863. std::string cmGlobalVisualStudio10Generator::GetInstalledNsightTegraVersion()
  864. {
  865. std::string version;
  866. cmSystemTools::ReadRegistryValue(
  867. "HKEY_LOCAL_MACHINE\\SOFTWARE\\NVIDIA Corporation\\Nsight Tegra;"
  868. "Version",
  869. version, cmSystemTools::KeyWOW64_32);
  870. return version;
  871. }
  872. cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetClFlagTable() const
  873. {
  874. cmIDEFlagTable const* table = this->ToolsetOptions.GetClFlagTable(
  875. this->GetPlatformName(), this->GetPlatformToolsetString());
  876. return (table != CM_NULLPTR) ? table : this->DefaultClFlagTable;
  877. }
  878. cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetCSharpFlagTable()
  879. const
  880. {
  881. cmIDEFlagTable const* table = this->ToolsetOptions.GetCSharpFlagTable(
  882. this->GetPlatformName(), this->GetPlatformToolsetString());
  883. return (table != CM_NULLPTR) ? table : this->DefaultCSharpFlagTable;
  884. }
  885. cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetRcFlagTable() const
  886. {
  887. cmIDEFlagTable const* table = this->ToolsetOptions.GetRcFlagTable(
  888. this->GetPlatformName(), this->GetPlatformToolsetString());
  889. return (table != CM_NULLPTR) ? table : this->DefaultRcFlagTable;
  890. }
  891. cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetLibFlagTable() const
  892. {
  893. cmIDEFlagTable const* table = this->ToolsetOptions.GetLibFlagTable(
  894. this->GetPlatformName(), this->GetPlatformToolsetString());
  895. return (table != CM_NULLPTR) ? table : this->DefaultLibFlagTable;
  896. }
  897. cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetLinkFlagTable() const
  898. {
  899. cmIDEFlagTable const* table = this->ToolsetOptions.GetLinkFlagTable(
  900. this->GetPlatformName(), this->GetPlatformToolsetString());
  901. return (table != CM_NULLPTR) ? table : this->DefaultLinkFlagTable;
  902. }
  903. cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetMasmFlagTable() const
  904. {
  905. cmIDEFlagTable const* table = this->ToolsetOptions.GetMasmFlagTable(
  906. this->GetPlatformName(), this->GetPlatformToolsetString());
  907. return (table != CM_NULLPTR) ? table : this->DefaultMasmFlagTable;
  908. }
  909. cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetNasmFlagTable() const
  910. {
  911. return this->DefaultNasmFlagTable;
  912. }