cmGlobalVisualStudioGenerator.cxx 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963
  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 "cmGlobalVisualStudioGenerator.h"
  4. #include "cmsys/Encoding.hxx"
  5. #include <future>
  6. #include <iostream>
  7. #include <objbase.h>
  8. #include <shellapi.h>
  9. #include <windows.h>
  10. #include "cmAlgorithms.h"
  11. #include "cmCallVisualStudioMacro.h"
  12. #include "cmGeneratedFileStream.h"
  13. #include "cmGeneratorTarget.h"
  14. #include "cmLocalVisualStudioGenerator.h"
  15. #include "cmMakefile.h"
  16. #include "cmSourceFile.h"
  17. #include "cmState.h"
  18. #include "cmTarget.h"
  19. cmGlobalVisualStudioGenerator::cmGlobalVisualStudioGenerator(cmake* cm)
  20. : cmGlobalGenerator(cm)
  21. {
  22. cm->GetState()->SetIsGeneratorMultiConfig(true);
  23. cm->GetState()->SetWindowsShell(true);
  24. cm->GetState()->SetWindowsVSIDE(true);
  25. }
  26. cmGlobalVisualStudioGenerator::~cmGlobalVisualStudioGenerator()
  27. {
  28. }
  29. cmGlobalVisualStudioGenerator::VSVersion
  30. cmGlobalVisualStudioGenerator::GetVersion() const
  31. {
  32. return this->Version;
  33. }
  34. void cmGlobalVisualStudioGenerator::SetVersion(VSVersion v)
  35. {
  36. this->Version = v;
  37. }
  38. std::string cmGlobalVisualStudioGenerator::GetRegistryBase()
  39. {
  40. return cmGlobalVisualStudioGenerator::GetRegistryBase(this->GetIDEVersion());
  41. }
  42. std::string cmGlobalVisualStudioGenerator::GetRegistryBase(const char* version)
  43. {
  44. std::string key = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\";
  45. return key + version;
  46. }
  47. void cmGlobalVisualStudioGenerator::AddExtraIDETargets()
  48. {
  49. // Add a special target that depends on ALL projects for easy build
  50. // of one configuration only.
  51. const char* no_working_dir = 0;
  52. std::vector<std::string> no_depends;
  53. cmCustomCommandLines no_commands;
  54. std::map<std::string, std::vector<cmLocalGenerator*>>::iterator it;
  55. for (it = this->ProjectMap.begin(); it != this->ProjectMap.end(); ++it) {
  56. std::vector<cmLocalGenerator*>& gen = it->second;
  57. // add the ALL_BUILD to the first local generator of each project
  58. if (!gen.empty()) {
  59. // Use no actual command lines so that the target itself is not
  60. // considered always out of date.
  61. cmTarget* allBuild = gen[0]->GetMakefile()->AddUtilityCommand(
  62. "ALL_BUILD", true, no_working_dir, no_depends, no_commands, false,
  63. "Build all projects");
  64. cmGeneratorTarget* gt = new cmGeneratorTarget(allBuild, gen[0]);
  65. gen[0]->AddGeneratorTarget(gt);
  66. //
  67. // Organize in the "predefined targets" folder:
  68. //
  69. if (this->UseFolderProperty()) {
  70. allBuild->SetProperty("FOLDER", this->GetPredefinedTargetsFolder());
  71. }
  72. // Now make all targets depend on the ALL_BUILD target
  73. for (std::vector<cmLocalGenerator*>::iterator i = gen.begin();
  74. i != gen.end(); ++i) {
  75. const std::vector<cmGeneratorTarget*>& targets =
  76. (*i)->GetGeneratorTargets();
  77. for (std::vector<cmGeneratorTarget*>::const_iterator t =
  78. targets.begin();
  79. t != targets.end(); ++t) {
  80. cmGeneratorTarget* tgt = *t;
  81. if (tgt->GetType() == cmStateEnums::GLOBAL_TARGET ||
  82. tgt->IsImported()) {
  83. continue;
  84. }
  85. if (!this->IsExcluded(gen[0], tgt)) {
  86. allBuild->AddUtility(tgt->GetName());
  87. }
  88. }
  89. }
  90. }
  91. }
  92. // Configure CMake Visual Studio macros, for this user on this version
  93. // of Visual Studio.
  94. this->ConfigureCMakeVisualStudioMacros();
  95. // Add CMakeLists.txt with custom command to rerun CMake.
  96. for (std::vector<cmLocalGenerator*>::const_iterator lgi =
  97. this->LocalGenerators.begin();
  98. lgi != this->LocalGenerators.end(); ++lgi) {
  99. cmLocalVisualStudioGenerator* lg =
  100. static_cast<cmLocalVisualStudioGenerator*>(*lgi);
  101. lg->AddCMakeListsRules();
  102. }
  103. }
  104. void cmGlobalVisualStudioGenerator::ComputeTargetObjectDirectory(
  105. cmGeneratorTarget* gt) const
  106. {
  107. std::string dir = gt->LocalGenerator->GetCurrentBinaryDirectory();
  108. dir += "/";
  109. std::string tgtDir = gt->LocalGenerator->GetTargetDirectory(gt);
  110. if (!tgtDir.empty()) {
  111. dir += tgtDir;
  112. dir += "/";
  113. }
  114. const char* cd = this->GetCMakeCFGIntDir();
  115. if (cd && *cd) {
  116. dir += cd;
  117. dir += "/";
  118. }
  119. gt->ObjectDirectory = dir;
  120. }
  121. bool IsVisualStudioMacrosFileRegistered(const std::string& macrosFile,
  122. const std::string& regKeyBase,
  123. std::string& nextAvailableSubKeyName);
  124. void RegisterVisualStudioMacros(const std::string& macrosFile,
  125. const std::string& regKeyBase);
  126. #define CMAKE_VSMACROS_FILENAME "CMakeVSMacros2.vsmacros"
  127. #define CMAKE_VSMACROS_RELOAD_MACRONAME \
  128. "Macros.CMakeVSMacros2.Macros.ReloadProjects"
  129. #define CMAKE_VSMACROS_STOP_MACRONAME "Macros.CMakeVSMacros2.Macros.StopBuild"
  130. void cmGlobalVisualStudioGenerator::ConfigureCMakeVisualStudioMacros()
  131. {
  132. std::string dir = this->GetUserMacrosDirectory();
  133. if (!dir.empty()) {
  134. std::string src = cmSystemTools::GetCMakeRoot();
  135. src += "/Templates/" CMAKE_VSMACROS_FILENAME;
  136. std::string dst = dir + "/CMakeMacros/" CMAKE_VSMACROS_FILENAME;
  137. // Copy the macros file to the user directory only if the
  138. // destination does not exist or the source location is newer.
  139. // This will allow the user to edit the macros for development
  140. // purposes but newer versions distributed with CMake will replace
  141. // older versions in user directories.
  142. int res;
  143. if (!cmSystemTools::FileTimeCompare(src.c_str(), dst.c_str(), &res) ||
  144. res > 0) {
  145. if (!cmSystemTools::CopyFileAlways(src.c_str(), dst.c_str())) {
  146. std::ostringstream oss;
  147. oss << "Could not copy from: " << src << std::endl;
  148. oss << " to: " << dst << std::endl;
  149. cmSystemTools::Message(oss.str().c_str(), "Warning");
  150. }
  151. }
  152. RegisterVisualStudioMacros(dst, this->GetUserMacrosRegKeyBase());
  153. }
  154. }
  155. void cmGlobalVisualStudioGenerator::CallVisualStudioMacro(
  156. MacroName m, const char* vsSolutionFile)
  157. {
  158. // If any solution or project files changed during the generation,
  159. // tell Visual Studio to reload them...
  160. cmMakefile* mf = this->LocalGenerators[0]->GetMakefile();
  161. std::string dir = this->GetUserMacrosDirectory();
  162. // Only really try to call the macro if:
  163. // - there is a UserMacrosDirectory
  164. // - the CMake vsmacros file exists
  165. // - the CMake vsmacros file is registered
  166. // - there were .sln/.vcproj files changed during generation
  167. //
  168. if (!dir.empty()) {
  169. std::string macrosFile = dir + "/CMakeMacros/" CMAKE_VSMACROS_FILENAME;
  170. std::string nextSubkeyName;
  171. if (cmSystemTools::FileExists(macrosFile.c_str()) &&
  172. IsVisualStudioMacrosFileRegistered(
  173. macrosFile, this->GetUserMacrosRegKeyBase(), nextSubkeyName)) {
  174. std::string topLevelSlnName;
  175. if (vsSolutionFile) {
  176. topLevelSlnName = vsSolutionFile;
  177. } else {
  178. topLevelSlnName = mf->GetCurrentBinaryDirectory();
  179. topLevelSlnName += "/";
  180. topLevelSlnName += this->LocalGenerators[0]->GetProjectName();
  181. topLevelSlnName += ".sln";
  182. }
  183. if (m == MacroReload) {
  184. std::vector<std::string> filenames;
  185. this->GetFilesReplacedDuringGenerate(filenames);
  186. if (!filenames.empty()) {
  187. // Convert vector to semi-colon delimited string of filenames:
  188. std::string projects;
  189. std::vector<std::string>::iterator it = filenames.begin();
  190. if (it != filenames.end()) {
  191. projects = *it;
  192. ++it;
  193. }
  194. for (; it != filenames.end(); ++it) {
  195. projects += ";";
  196. projects += *it;
  197. }
  198. cmCallVisualStudioMacro::CallMacro(
  199. topLevelSlnName, CMAKE_VSMACROS_RELOAD_MACRONAME, projects,
  200. this->GetCMakeInstance()->GetDebugOutput());
  201. }
  202. } else if (m == MacroStop) {
  203. cmCallVisualStudioMacro::CallMacro(
  204. topLevelSlnName, CMAKE_VSMACROS_STOP_MACRONAME, "",
  205. this->GetCMakeInstance()->GetDebugOutput());
  206. }
  207. }
  208. }
  209. }
  210. std::string cmGlobalVisualStudioGenerator::GetUserMacrosDirectory()
  211. {
  212. return "";
  213. }
  214. std::string cmGlobalVisualStudioGenerator::GetUserMacrosRegKeyBase()
  215. {
  216. return "";
  217. }
  218. void cmGlobalVisualStudioGenerator::FillLinkClosure(
  219. const cmGeneratorTarget* target, TargetSet& linked)
  220. {
  221. if (linked.insert(target).second) {
  222. TargetDependSet const& depends = this->GetTargetDirectDepends(target);
  223. for (TargetDependSet::const_iterator di = depends.begin();
  224. di != depends.end(); ++di) {
  225. if (di->IsLink()) {
  226. this->FillLinkClosure(*di, linked);
  227. }
  228. }
  229. }
  230. }
  231. cmGlobalVisualStudioGenerator::TargetSet const&
  232. cmGlobalVisualStudioGenerator::GetTargetLinkClosure(cmGeneratorTarget* target)
  233. {
  234. TargetSetMap::iterator i = this->TargetLinkClosure.find(target);
  235. if (i == this->TargetLinkClosure.end()) {
  236. TargetSetMap::value_type entry(target, TargetSet());
  237. i = this->TargetLinkClosure.insert(entry).first;
  238. this->FillLinkClosure(target, i->second);
  239. }
  240. return i->second;
  241. }
  242. void cmGlobalVisualStudioGenerator::FollowLinkDepends(
  243. const cmGeneratorTarget* target, std::set<const cmGeneratorTarget*>& linked)
  244. {
  245. if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
  246. return;
  247. }
  248. if (linked.insert(target).second &&
  249. target->GetType() == cmStateEnums::STATIC_LIBRARY) {
  250. // Static library targets do not list their link dependencies so
  251. // we must follow them transitively now.
  252. TargetDependSet const& depends = this->GetTargetDirectDepends(target);
  253. for (TargetDependSet::const_iterator di = depends.begin();
  254. di != depends.end(); ++di) {
  255. if (di->IsLink()) {
  256. this->FollowLinkDepends(*di, linked);
  257. }
  258. }
  259. }
  260. }
  261. bool cmGlobalVisualStudioGenerator::ComputeTargetDepends()
  262. {
  263. if (!this->cmGlobalGenerator::ComputeTargetDepends()) {
  264. return false;
  265. }
  266. std::map<std::string, std::vector<cmLocalGenerator*>>::iterator it;
  267. for (it = this->ProjectMap.begin(); it != this->ProjectMap.end(); ++it) {
  268. std::vector<cmLocalGenerator*>& gen = it->second;
  269. for (std::vector<cmLocalGenerator*>::iterator i = gen.begin();
  270. i != gen.end(); ++i) {
  271. const std::vector<cmGeneratorTarget*>& targets =
  272. (*i)->GetGeneratorTargets();
  273. for (std::vector<cmGeneratorTarget*>::const_iterator ti =
  274. targets.begin();
  275. ti != targets.end(); ++ti) {
  276. this->ComputeVSTargetDepends(*ti);
  277. }
  278. }
  279. }
  280. return true;
  281. }
  282. static bool VSLinkable(cmGeneratorTarget const* t)
  283. {
  284. return t->IsLinkable() || t->GetType() == cmStateEnums::OBJECT_LIBRARY;
  285. }
  286. void cmGlobalVisualStudioGenerator::ComputeVSTargetDepends(
  287. cmGeneratorTarget* target)
  288. {
  289. if (this->VSTargetDepends.find(target) != this->VSTargetDepends.end()) {
  290. return;
  291. }
  292. VSDependSet& vsTargetDepend = this->VSTargetDepends[target];
  293. // VS <= 7.1 has two behaviors that affect solution dependencies.
  294. //
  295. // (1) Solution-level dependencies between a linkable target and a
  296. // library cause that library to be linked. We use an intermedite
  297. // empty utility target to express the dependency. (VS 8 and above
  298. // provide a project file "LinkLibraryDependencies" setting to
  299. // choose whether to activate this behavior. We disable it except
  300. // when linking external project files.)
  301. //
  302. // (2) We cannot let static libraries depend directly on targets to
  303. // which they "link" because the librarian tool will copy the
  304. // targets into the static library. While the work-around for
  305. // behavior (1) would also avoid this, it would create a large
  306. // number of extra utility targets for little gain. Instead, use
  307. // the above work-around only for dependencies explicitly added by
  308. // the add_dependencies() command. Approximate link dependencies by
  309. // leaving them out for the static library itself but following them
  310. // transitively for other targets.
  311. bool allowLinkable = (target->GetType() != cmStateEnums::STATIC_LIBRARY &&
  312. target->GetType() != cmStateEnums::SHARED_LIBRARY &&
  313. target->GetType() != cmStateEnums::MODULE_LIBRARY &&
  314. target->GetType() != cmStateEnums::EXECUTABLE);
  315. TargetDependSet const& depends = this->GetTargetDirectDepends(target);
  316. // Collect implicit link dependencies (target_link_libraries).
  317. // Static libraries cannot depend on their link implementation
  318. // due to behavior (2), but they do not really need to.
  319. std::set<cmGeneratorTarget const*> linkDepends;
  320. if (target->GetType() != cmStateEnums::STATIC_LIBRARY) {
  321. for (TargetDependSet::const_iterator di = depends.begin();
  322. di != depends.end(); ++di) {
  323. cmTargetDepend dep = *di;
  324. if (dep.IsLink()) {
  325. this->FollowLinkDepends(*di, linkDepends);
  326. }
  327. }
  328. }
  329. // Collect explicit util dependencies (add_dependencies).
  330. std::set<cmGeneratorTarget const*> utilDepends;
  331. for (TargetDependSet::const_iterator di = depends.begin();
  332. di != depends.end(); ++di) {
  333. cmTargetDepend dep = *di;
  334. if (dep.IsUtil()) {
  335. this->FollowLinkDepends(*di, utilDepends);
  336. }
  337. }
  338. // Collect all targets linked by this target so we can avoid
  339. // intermediate targets below.
  340. TargetSet linked;
  341. if (target->GetType() != cmStateEnums::STATIC_LIBRARY) {
  342. linked = this->GetTargetLinkClosure(target);
  343. }
  344. // Emit link dependencies.
  345. for (std::set<cmGeneratorTarget const*>::iterator di = linkDepends.begin();
  346. di != linkDepends.end(); ++di) {
  347. cmGeneratorTarget const* dep = *di;
  348. vsTargetDepend.insert(dep->GetName());
  349. }
  350. // Emit util dependencies. Possibly use intermediate targets.
  351. for (std::set<cmGeneratorTarget const*>::iterator di = utilDepends.begin();
  352. di != utilDepends.end(); ++di) {
  353. cmGeneratorTarget const* dgt = *di;
  354. if (allowLinkable || !VSLinkable(dgt) || linked.count(dgt)) {
  355. // Direct dependency allowed.
  356. vsTargetDepend.insert(dgt->GetName());
  357. } else {
  358. // Direct dependency on linkable target not allowed.
  359. // Use an intermediate utility target.
  360. vsTargetDepend.insert(this->GetUtilityDepend(dgt));
  361. }
  362. }
  363. }
  364. bool cmGlobalVisualStudioGenerator::FindMakeProgram(cmMakefile* mf)
  365. {
  366. // Visual Studio generators know how to lookup their build tool
  367. // directly instead of needing a helper module to do it, so we
  368. // do not actually need to put CMAKE_MAKE_PROGRAM into the cache.
  369. if (cmSystemTools::IsOff(mf->GetDefinition("CMAKE_MAKE_PROGRAM"))) {
  370. mf->AddDefinition("CMAKE_MAKE_PROGRAM", this->GetVSMakeProgram().c_str());
  371. }
  372. return true;
  373. }
  374. std::string cmGlobalVisualStudioGenerator::GetUtilityDepend(
  375. cmGeneratorTarget const* target)
  376. {
  377. UtilityDependsMap::iterator i = this->UtilityDepends.find(target);
  378. if (i == this->UtilityDepends.end()) {
  379. std::string name = this->WriteUtilityDepend(target);
  380. UtilityDependsMap::value_type entry(target, name);
  381. i = this->UtilityDepends.insert(entry).first;
  382. }
  383. return i->second;
  384. }
  385. std::string cmGlobalVisualStudioGenerator::GetStartupProjectName(
  386. cmLocalGenerator const* root) const
  387. {
  388. const char* n = root->GetMakefile()->GetProperty("VS_STARTUP_PROJECT");
  389. if (n && *n) {
  390. std::string startup = n;
  391. if (this->FindTarget(startup)) {
  392. return startup;
  393. } else {
  394. root->GetMakefile()->IssueMessage(
  395. cmake::AUTHOR_WARNING,
  396. "Directory property VS_STARTUP_PROJECT specifies target "
  397. "'" +
  398. startup + "' that does not exist. Ignoring.");
  399. }
  400. }
  401. // default, if not specified
  402. return this->GetAllTargetName();
  403. }
  404. bool IsVisualStudioMacrosFileRegistered(const std::string& macrosFile,
  405. const std::string& regKeyBase,
  406. std::string& nextAvailableSubKeyName)
  407. {
  408. bool macrosRegistered = false;
  409. std::string s1;
  410. std::string s2;
  411. // Make lowercase local copies, convert to Unix slashes, and
  412. // see if the resulting strings are the same:
  413. s1 = cmSystemTools::LowerCase(macrosFile);
  414. cmSystemTools::ConvertToUnixSlashes(s1);
  415. std::string keyname;
  416. HKEY hkey = NULL;
  417. LONG result = ERROR_SUCCESS;
  418. DWORD index = 0;
  419. keyname = regKeyBase + "\\OtherProjects7";
  420. hkey = NULL;
  421. result =
  422. RegOpenKeyExW(HKEY_CURRENT_USER, cmsys::Encoding::ToWide(keyname).c_str(),
  423. 0, KEY_READ, &hkey);
  424. if (ERROR_SUCCESS == result) {
  425. // Iterate the subkeys and look for the values of interest in each subkey:
  426. wchar_t subkeyname[256];
  427. DWORD cch_subkeyname = sizeof(subkeyname) * sizeof(subkeyname[0]);
  428. wchar_t keyclass[256];
  429. DWORD cch_keyclass = sizeof(keyclass) * sizeof(keyclass[0]);
  430. FILETIME lastWriteTime;
  431. lastWriteTime.dwHighDateTime = 0;
  432. lastWriteTime.dwLowDateTime = 0;
  433. while (ERROR_SUCCESS == RegEnumKeyExW(hkey, index, subkeyname,
  434. &cch_subkeyname, 0, keyclass,
  435. &cch_keyclass, &lastWriteTime)) {
  436. // Open the subkey and query the values of interest:
  437. HKEY hsubkey = NULL;
  438. result = RegOpenKeyExW(hkey, subkeyname, 0, KEY_READ, &hsubkey);
  439. if (ERROR_SUCCESS == result) {
  440. DWORD valueType = REG_SZ;
  441. wchar_t data1[256];
  442. DWORD cch_data1 = sizeof(data1) * sizeof(data1[0]);
  443. RegQueryValueExW(hsubkey, L"Path", 0, &valueType, (LPBYTE)&data1[0],
  444. &cch_data1);
  445. DWORD data2 = 0;
  446. DWORD cch_data2 = sizeof(data2);
  447. RegQueryValueExW(hsubkey, L"Security", 0, &valueType, (LPBYTE)&data2,
  448. &cch_data2);
  449. DWORD data3 = 0;
  450. DWORD cch_data3 = sizeof(data3);
  451. RegQueryValueExW(hsubkey, L"StorageFormat", 0, &valueType,
  452. (LPBYTE)&data3, &cch_data3);
  453. s2 = cmSystemTools::LowerCase(cmsys::Encoding::ToNarrow(data1));
  454. cmSystemTools::ConvertToUnixSlashes(s2);
  455. if (s2 == s1) {
  456. macrosRegistered = true;
  457. }
  458. std::string fullname = cmsys::Encoding::ToNarrow(data1);
  459. std::string filename;
  460. std::string filepath;
  461. std::string filepathname;
  462. std::string filepathpath;
  463. if (cmSystemTools::FileExists(fullname.c_str())) {
  464. filename = cmSystemTools::GetFilenameName(fullname);
  465. filepath = cmSystemTools::GetFilenamePath(fullname);
  466. filepathname = cmSystemTools::GetFilenameName(filepath);
  467. filepathpath = cmSystemTools::GetFilenamePath(filepath);
  468. }
  469. // std::cout << keyname << "\\" << subkeyname << ":" << std::endl;
  470. // std::cout << " Path: " << data1 << std::endl;
  471. // std::cout << " Security: " << data2 << std::endl;
  472. // std::cout << " StorageFormat: " << data3 << std::endl;
  473. // std::cout << " filename: " << filename << std::endl;
  474. // std::cout << " filepath: " << filepath << std::endl;
  475. // std::cout << " filepathname: " << filepathname << std::endl;
  476. // std::cout << " filepathpath: " << filepathpath << std::endl;
  477. // std::cout << std::endl;
  478. RegCloseKey(hsubkey);
  479. } else {
  480. std::cout << "error opening subkey: " << subkeyname << std::endl;
  481. std::cout << std::endl;
  482. }
  483. ++index;
  484. cch_subkeyname = sizeof(subkeyname) * sizeof(subkeyname[0]);
  485. cch_keyclass = sizeof(keyclass) * sizeof(keyclass[0]);
  486. lastWriteTime.dwHighDateTime = 0;
  487. lastWriteTime.dwLowDateTime = 0;
  488. }
  489. RegCloseKey(hkey);
  490. } else {
  491. std::cout << "error opening key: " << keyname << std::endl;
  492. std::cout << std::endl;
  493. }
  494. // Pass back next available sub key name, assuming sub keys always
  495. // follow the expected naming scheme. Expected naming scheme is that
  496. // the subkeys of OtherProjects7 is 0 to n-1, so it's ok to use "n"
  497. // as the name of the next subkey.
  498. std::ostringstream ossNext;
  499. ossNext << index;
  500. nextAvailableSubKeyName = ossNext.str();
  501. keyname = regKeyBase + "\\RecordingProject7";
  502. hkey = NULL;
  503. result =
  504. RegOpenKeyExW(HKEY_CURRENT_USER, cmsys::Encoding::ToWide(keyname).c_str(),
  505. 0, KEY_READ, &hkey);
  506. if (ERROR_SUCCESS == result) {
  507. DWORD valueType = REG_SZ;
  508. wchar_t data1[256];
  509. DWORD cch_data1 = sizeof(data1) * sizeof(data1[0]);
  510. RegQueryValueExW(hkey, L"Path", 0, &valueType, (LPBYTE)&data1[0],
  511. &cch_data1);
  512. DWORD data2 = 0;
  513. DWORD cch_data2 = sizeof(data2);
  514. RegQueryValueExW(hkey, L"Security", 0, &valueType, (LPBYTE)&data2,
  515. &cch_data2);
  516. DWORD data3 = 0;
  517. DWORD cch_data3 = sizeof(data3);
  518. RegQueryValueExW(hkey, L"StorageFormat", 0, &valueType, (LPBYTE)&data3,
  519. &cch_data3);
  520. s2 = cmSystemTools::LowerCase(cmsys::Encoding::ToNarrow(data1));
  521. cmSystemTools::ConvertToUnixSlashes(s2);
  522. if (s2 == s1) {
  523. macrosRegistered = true;
  524. }
  525. // std::cout << keyname << ":" << std::endl;
  526. // std::cout << " Path: " << data1 << std::endl;
  527. // std::cout << " Security: " << data2 << std::endl;
  528. // std::cout << " StorageFormat: " << data3 << std::endl;
  529. // std::cout << std::endl;
  530. RegCloseKey(hkey);
  531. } else {
  532. std::cout << "error opening key: " << keyname << std::endl;
  533. std::cout << std::endl;
  534. }
  535. return macrosRegistered;
  536. }
  537. void WriteVSMacrosFileRegistryEntry(const std::string& nextAvailableSubKeyName,
  538. const std::string& macrosFile,
  539. const std::string& regKeyBase)
  540. {
  541. std::string keyname = regKeyBase + "\\OtherProjects7";
  542. HKEY hkey = NULL;
  543. LONG result =
  544. RegOpenKeyExW(HKEY_CURRENT_USER, cmsys::Encoding::ToWide(keyname).c_str(),
  545. 0, KEY_READ | KEY_WRITE, &hkey);
  546. if (ERROR_SUCCESS == result) {
  547. // Create the subkey and set the values of interest:
  548. HKEY hsubkey = NULL;
  549. wchar_t lpClass[] = L"";
  550. result = RegCreateKeyExW(
  551. hkey, cmsys::Encoding::ToWide(nextAvailableSubKeyName).c_str(), 0,
  552. lpClass, 0, KEY_READ | KEY_WRITE, 0, &hsubkey, 0);
  553. if (ERROR_SUCCESS == result) {
  554. DWORD dw = 0;
  555. std::string s(macrosFile);
  556. std::replace(s.begin(), s.end(), '/', '\\');
  557. std::wstring ws = cmsys::Encoding::ToWide(s);
  558. result =
  559. RegSetValueExW(hsubkey, L"Path", 0, REG_SZ, (LPBYTE)ws.c_str(),
  560. static_cast<DWORD>(ws.size() + 1) * sizeof(wchar_t));
  561. if (ERROR_SUCCESS != result) {
  562. std::cout << "error result 1: " << result << std::endl;
  563. std::cout << std::endl;
  564. }
  565. // Security value is always "1" for sample macros files (seems to be "2"
  566. // if you put the file somewhere outside the standard VSMacros folder)
  567. dw = 1;
  568. result = RegSetValueExW(hsubkey, L"Security", 0, REG_DWORD, (LPBYTE)&dw,
  569. sizeof(DWORD));
  570. if (ERROR_SUCCESS != result) {
  571. std::cout << "error result 2: " << result << std::endl;
  572. std::cout << std::endl;
  573. }
  574. // StorageFormat value is always "0" for sample macros files
  575. dw = 0;
  576. result = RegSetValueExW(hsubkey, L"StorageFormat", 0, REG_DWORD,
  577. (LPBYTE)&dw, sizeof(DWORD));
  578. if (ERROR_SUCCESS != result) {
  579. std::cout << "error result 3: " << result << std::endl;
  580. std::cout << std::endl;
  581. }
  582. RegCloseKey(hsubkey);
  583. } else {
  584. std::cout << "error creating subkey: " << nextAvailableSubKeyName
  585. << std::endl;
  586. std::cout << std::endl;
  587. }
  588. RegCloseKey(hkey);
  589. } else {
  590. std::cout << "error opening key: " << keyname << std::endl;
  591. std::cout << std::endl;
  592. }
  593. }
  594. void RegisterVisualStudioMacros(const std::string& macrosFile,
  595. const std::string& regKeyBase)
  596. {
  597. bool macrosRegistered;
  598. std::string nextAvailableSubKeyName;
  599. macrosRegistered = IsVisualStudioMacrosFileRegistered(
  600. macrosFile, regKeyBase, nextAvailableSubKeyName);
  601. if (!macrosRegistered) {
  602. int count =
  603. cmCallVisualStudioMacro::GetNumberOfRunningVisualStudioInstances("ALL");
  604. // Only register the macros file if there are *no* instances of Visual
  605. // Studio running. If we register it while one is running, first, it has
  606. // no effect on the running instance; second, and worse, Visual Studio
  607. // removes our newly added registration entry when it quits. Instead,
  608. // emit a warning asking the user to exit all running Visual Studio
  609. // instances...
  610. //
  611. if (0 != count) {
  612. std::ostringstream oss;
  613. oss << "Could not register CMake's Visual Studio macros file '"
  614. << CMAKE_VSMACROS_FILENAME "' while Visual Studio is running."
  615. << " Please exit all running instances of Visual Studio before"
  616. << " continuing." << std::endl
  617. << std::endl
  618. << "CMake needs to register Visual Studio macros when its macros"
  619. << " file is updated or when it detects that its current macros file"
  620. << " is no longer registered with Visual Studio." << std::endl;
  621. cmSystemTools::Message(oss.str().c_str(), "Warning");
  622. // Count them again now that the warning is over. In the case of a GUI
  623. // warning, the user may have gone to close Visual Studio and then come
  624. // back to the CMake GUI and clicked ok on the above warning. If so,
  625. // then register the macros *now* if the count is *now* 0...
  626. //
  627. count = cmCallVisualStudioMacro::GetNumberOfRunningVisualStudioInstances(
  628. "ALL");
  629. // Also re-get the nextAvailableSubKeyName in case Visual Studio
  630. // wrote out new registered macros information as it was exiting:
  631. //
  632. if (0 == count) {
  633. IsVisualStudioMacrosFileRegistered(macrosFile, regKeyBase,
  634. nextAvailableSubKeyName);
  635. }
  636. }
  637. // Do another if check - 'count' may have changed inside the above if:
  638. //
  639. if (0 == count) {
  640. WriteVSMacrosFileRegistryEntry(nextAvailableSubKeyName, macrosFile,
  641. regKeyBase);
  642. }
  643. }
  644. }
  645. bool cmGlobalVisualStudioGenerator::TargetIsFortranOnly(
  646. cmGeneratorTarget const* gt)
  647. {
  648. // check to see if this is a fortran build
  649. std::set<std::string> languages;
  650. {
  651. // Issue diagnostic if the source files depend on the config.
  652. std::vector<cmSourceFile*> sources;
  653. if (!gt->GetConfigCommonSourceFiles(sources)) {
  654. return false;
  655. }
  656. }
  657. // If there's only one source language, Fortran has to be used
  658. // in order for the sources to compile.
  659. // Note: Via linker propagation, LINKER_LANGUAGE could become CXX in
  660. // this situation and mismatch from the actual language of the linker.
  661. gt->GetLanguages(languages, "");
  662. if (languages.size() == 1) {
  663. if (*languages.begin() == "Fortran") {
  664. return true;
  665. }
  666. }
  667. // In the case of mixed object files or sources mixed with objects,
  668. // decide the language based on the value of LINKER_LANGUAGE.
  669. // This will not make it possible to mix source files of different
  670. // languages, but object libraries will be linked together in the
  671. // same fashion as other generators do.
  672. if (gt->GetLinkerLanguage("") == "Fortran") {
  673. return true;
  674. }
  675. return false;
  676. }
  677. bool cmGlobalVisualStudioGenerator::TargetIsCSharpOnly(
  678. cmGeneratorTarget const* gt)
  679. {
  680. // check to see if this is a C# build
  681. std::set<std::string> languages;
  682. {
  683. // Issue diagnostic if the source files depend on the config.
  684. std::vector<cmSourceFile*> sources;
  685. if (!gt->GetConfigCommonSourceFiles(sources)) {
  686. return false;
  687. }
  688. // Only "real" targets are allowed to be C# targets.
  689. if (gt->Target->GetType() > cmStateEnums::OBJECT_LIBRARY) {
  690. return false;
  691. }
  692. }
  693. gt->GetLanguages(languages, "");
  694. if (languages.size() == 1) {
  695. if (*languages.begin() == "CSharp") {
  696. return true;
  697. }
  698. }
  699. return false;
  700. }
  701. bool cmGlobalVisualStudioGenerator::TargetCanBeReferenced(
  702. cmGeneratorTarget const* gt)
  703. {
  704. if (this->TargetIsCSharpOnly(gt)) {
  705. return true;
  706. }
  707. if (gt->GetType() != cmStateEnums::SHARED_LIBRARY &&
  708. gt->GetType() != cmStateEnums::EXECUTABLE) {
  709. return false;
  710. }
  711. return true;
  712. }
  713. bool cmGlobalVisualStudioGenerator::TargetCompare::operator()(
  714. cmGeneratorTarget const* l, cmGeneratorTarget const* r) const
  715. {
  716. // Make sure a given named target is ordered first,
  717. // e.g. to set ALL_BUILD as the default active project.
  718. // When the empty string is named this is a no-op.
  719. if (r->GetName() == this->First) {
  720. return false;
  721. }
  722. if (l->GetName() == this->First) {
  723. return true;
  724. }
  725. return l->GetName() < r->GetName();
  726. }
  727. cmGlobalVisualStudioGenerator::OrderedTargetDependSet::OrderedTargetDependSet(
  728. TargetDependSet const& targets, std::string const& first)
  729. : derived(TargetCompare(first))
  730. {
  731. this->insert(targets.begin(), targets.end());
  732. }
  733. cmGlobalVisualStudioGenerator::OrderedTargetDependSet::OrderedTargetDependSet(
  734. TargetSet const& targets, std::string const& first)
  735. : derived(TargetCompare(first))
  736. {
  737. for (TargetSet::const_iterator it = targets.begin(); it != targets.end();
  738. ++it) {
  739. this->insert(*it);
  740. }
  741. }
  742. std::string cmGlobalVisualStudioGenerator::ExpandCFGIntDir(
  743. const std::string& str, const std::string& config) const
  744. {
  745. std::string replace = GetCMakeCFGIntDir();
  746. std::string tmp = str;
  747. for (std::string::size_type i = tmp.find(replace); i != std::string::npos;
  748. i = tmp.find(replace, i)) {
  749. tmp.replace(i, replace.size(), config);
  750. i += config.size();
  751. }
  752. return tmp;
  753. }
  754. void cmGlobalVisualStudioGenerator::AddSymbolExportCommand(
  755. cmGeneratorTarget* gt, std::vector<cmCustomCommand>& commands,
  756. std::string const& configName)
  757. {
  758. cmGeneratorTarget::ModuleDefinitionInfo const* mdi =
  759. gt->GetModuleDefinitionInfo(configName);
  760. if (!mdi || !mdi->DefFileGenerated) {
  761. return;
  762. }
  763. std::vector<std::string> outputs;
  764. outputs.push_back(mdi->DefFile);
  765. std::vector<std::string> empty;
  766. std::vector<cmSourceFile const*> objectSources;
  767. gt->GetObjectSources(objectSources, configName);
  768. std::map<cmSourceFile const*, std::string> mapping;
  769. for (std::vector<cmSourceFile const*>::const_iterator it =
  770. objectSources.begin();
  771. it != objectSources.end(); ++it) {
  772. mapping[*it];
  773. }
  774. gt->LocalGenerator->ComputeObjectFilenames(mapping, gt);
  775. std::string obj_dir = gt->ObjectDirectory;
  776. std::string cmakeCommand = cmSystemTools::GetCMakeCommand();
  777. cmSystemTools::ConvertToWindowsExtendedPath(cmakeCommand);
  778. cmCustomCommandLine cmdl;
  779. cmdl.push_back(cmakeCommand);
  780. cmdl.push_back("-E");
  781. cmdl.push_back("__create_def");
  782. cmdl.push_back(mdi->DefFile);
  783. std::string obj_dir_expanded = obj_dir;
  784. cmSystemTools::ReplaceString(obj_dir_expanded, this->GetCMakeCFGIntDir(),
  785. configName.c_str());
  786. cmSystemTools::MakeDirectory(obj_dir_expanded);
  787. std::string const objs_file = obj_dir_expanded + "/objects.txt";
  788. cmdl.push_back(objs_file);
  789. cmGeneratedFileStream fout(objs_file.c_str());
  790. if (!fout) {
  791. cmSystemTools::Error("could not open ", objs_file.c_str());
  792. return;
  793. }
  794. if (mdi->WindowsExportAllSymbols) {
  795. std::vector<std::string> objs;
  796. for (std::vector<cmSourceFile const*>::const_iterator it =
  797. objectSources.begin();
  798. it != objectSources.end(); ++it) {
  799. // Find the object file name corresponding to this source file.
  800. std::map<cmSourceFile const*, std::string>::const_iterator map_it =
  801. mapping.find(*it);
  802. // It must exist because we populated the mapping just above.
  803. assert(!map_it->second.empty());
  804. std::string objFile = obj_dir + map_it->second;
  805. objs.push_back(objFile);
  806. }
  807. std::vector<cmSourceFile const*> externalObjectSources;
  808. gt->GetExternalObjects(externalObjectSources, configName);
  809. for (std::vector<cmSourceFile const*>::const_iterator it =
  810. externalObjectSources.begin();
  811. it != externalObjectSources.end(); ++it) {
  812. objs.push_back((*it)->GetFullPath());
  813. }
  814. for (std::vector<std::string>::iterator it = objs.begin();
  815. it != objs.end(); ++it) {
  816. std::string objFile = *it;
  817. // replace $(ConfigurationName) in the object names
  818. cmSystemTools::ReplaceString(objFile, this->GetCMakeCFGIntDir(),
  819. configName.c_str());
  820. if (cmHasLiteralSuffix(objFile, ".obj")) {
  821. fout << objFile << "\n";
  822. }
  823. }
  824. }
  825. for (std::vector<cmSourceFile const*>::const_iterator i =
  826. mdi->Sources.begin();
  827. i != mdi->Sources.end(); ++i) {
  828. fout << (*i)->GetFullPath() << "\n";
  829. }
  830. cmCustomCommandLines commandLines;
  831. commandLines.push_back(cmdl);
  832. cmCustomCommand command(gt->Target->GetMakefile(), outputs, empty, empty,
  833. commandLines, "Auto build dll exports", ".");
  834. commands.push_back(command);
  835. }
  836. static bool OpenSolution(std::string sln)
  837. {
  838. HRESULT comInitialized =
  839. CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
  840. if (FAILED(comInitialized)) {
  841. return false;
  842. }
  843. HINSTANCE hi =
  844. ShellExecuteA(NULL, "open", sln.c_str(), NULL, NULL, SW_SHOWNORMAL);
  845. CoUninitialize();
  846. return reinterpret_cast<intptr_t>(hi) > 32;
  847. }
  848. bool cmGlobalVisualStudioGenerator::Open(const std::string& bindir,
  849. const std::string& projectName,
  850. bool dryRun)
  851. {
  852. std::string buildDir = cmSystemTools::ConvertToOutputPath(bindir.c_str());
  853. std::string sln = buildDir + "\\" + projectName + ".sln";
  854. if (dryRun) {
  855. return cmSystemTools::FileExists(sln, true);
  856. }
  857. return std::async(std::launch::async, OpenSolution, sln).get();
  858. }