1 /*============================================================================
2 CMake - Cross Platform Makefile Generator
3 Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
5 Distributed under the OSI-approved BSD License (the "License");
6 see accompanying file Copyright.txt for details.
8 This software is distributed WITHOUT ANY WARRANTY; without even the
9 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10 See the License for more information.
11 ============================================================================*/
12 #include "cmGlobalVisualStudioGenerator.h"
14 #include "cmCallVisualStudioMacro.h"
15 #include "cmGeneratorTarget.h"
16 #include "cmLocalVisualStudioGenerator.h"
17 #include "cmMakefile.h"
18 #include "cmSourceFile.h"
21 //----------------------------------------------------------------------------
22 cmGlobalVisualStudioGenerator::cmGlobalVisualStudioGenerator()
24 this->AdditionalPlatformDefinition = NULL;
27 //----------------------------------------------------------------------------
28 cmGlobalVisualStudioGenerator::~cmGlobalVisualStudioGenerator()
32 //----------------------------------------------------------------------------
33 std::string cmGlobalVisualStudioGenerator::GetRegistryBase()
35 return cmGlobalVisualStudioGenerator::GetRegistryBase(
36 this->GetIDEVersion());
39 //----------------------------------------------------------------------------
40 std::string cmGlobalVisualStudioGenerator::GetRegistryBase(
43 std::string key = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\";
47 //----------------------------------------------------------------------------
48 void cmGlobalVisualStudioGenerator::Generate()
50 // Add a special target that depends on ALL projects for easy build
51 // of one configuration only.
52 const char* no_working_dir = 0;
53 std::vector<std::string> no_depends;
54 cmCustomCommandLines no_commands;
55 std::map<cmStdString, std::vector<cmLocalGenerator*> >::iterator it;
56 for(it = this->ProjectMap.begin(); it!= this->ProjectMap.end(); ++it)
58 std::vector<cmLocalGenerator*>& gen = it->second;
59 // add the ALL_BUILD to the first local generator of each project
62 // Use no actual command lines so that the target itself is not
63 // considered always out of date.
65 gen[0]->GetMakefile()->
66 AddUtilityCommand("ALL_BUILD", true, no_working_dir,
67 no_depends, no_commands, false,
68 "Build all projects");
71 // Can't activate this code because we want ALL_BUILD
72 // selected as the default "startup project" when first
73 // opened in Visual Studio... And if it's nested in a
74 // folder, then that doesn't happen.
76 // Organize in the "predefined targets" folder:
78 if (this->UseFolderProperty())
80 allBuild->SetProperty("FOLDER", this->GetPredefinedTargetsFolder());
84 // Now make all targets depend on the ALL_BUILD target
85 for(std::vector<cmLocalGenerator*>::iterator i = gen.begin();
88 cmTargets& targets = (*i)->GetMakefile()->GetTargets();
89 for(cmTargets::iterator t = targets.begin();
90 t != targets.end(); ++t)
92 if(!this->IsExcluded(gen[0], t->second))
94 allBuild->AddUtility(t->second.GetName());
101 // Configure CMake Visual Studio macros, for this user on this version
103 this->ConfigureCMakeVisualStudioMacros();
105 // Add CMakeLists.txt with custom command to rerun CMake.
106 for(std::vector<cmLocalGenerator*>::const_iterator
107 lgi = this->LocalGenerators.begin();
108 lgi != this->LocalGenerators.end(); ++lgi)
110 cmLocalVisualStudioGenerator* lg =
111 static_cast<cmLocalVisualStudioGenerator*>(*lgi);
112 lg->AddCMakeListsRules();
115 // Run all the local generators.
116 this->cmGlobalGenerator::Generate();
119 //----------------------------------------------------------------------------
121 cmGlobalVisualStudioGenerator
122 ::ComputeTargetObjects(cmGeneratorTarget* gt) const
124 cmLocalVisualStudioGenerator* lg =
125 static_cast<cmLocalVisualStudioGenerator*>(gt->LocalGenerator);
126 std::string dir_max = lg->ComputeLongestObjectDirectory(*gt->Target);
128 // Count the number of object files with each name. Note that
129 // windows file names are not case sensitive.
130 std::map<cmStdString, int> counts;
131 for(std::vector<cmSourceFile*>::const_iterator
132 si = gt->ObjectSources.begin();
133 si != gt->ObjectSources.end(); ++si)
135 cmSourceFile* sf = *si;
136 std::string objectNameLower = cmSystemTools::LowerCase(
137 cmSystemTools::GetFilenameWithoutLastExtension(sf->GetFullPath()));
138 objectNameLower += ".obj";
139 counts[objectNameLower] += 1;
142 // For all source files producing duplicate names we need unique
143 // object name computation.
144 for(std::vector<cmSourceFile*>::const_iterator
145 si = gt->ObjectSources.begin();
146 si != gt->ObjectSources.end(); ++si)
148 cmSourceFile* sf = *si;
149 std::string objectName =
150 cmSystemTools::GetFilenameWithoutLastExtension(sf->GetFullPath());
151 objectName += ".obj";
152 if(counts[cmSystemTools::LowerCase(objectName)] > 1)
154 gt->ExplicitObjectName.insert(sf);
155 objectName = lg->GetObjectFileNameWithoutTarget(*sf, dir_max);
157 gt->Objects[sf] = objectName;
160 std::string dir = gt->Makefile->GetCurrentOutputDirectory();
162 std::string tgtDir = lg->GetTargetDirectory(*gt->Target);
168 const char* cd = this->GetCMakeCFGIntDir();
174 gt->ObjectDirectory = dir;
177 //----------------------------------------------------------------------------
178 bool IsVisualStudioMacrosFileRegistered(const std::string& macrosFile,
179 const std::string& regKeyBase,
180 std::string& nextAvailableSubKeyName);
182 void RegisterVisualStudioMacros(const std::string& macrosFile,
183 const std::string& regKeyBase);
185 //----------------------------------------------------------------------------
186 #define CMAKE_VSMACROS_FILENAME \
187 "CMakeVSMacros2.vsmacros"
189 #define CMAKE_VSMACROS_RELOAD_MACRONAME \
190 "Macros.CMakeVSMacros2.Macros.ReloadProjects"
192 #define CMAKE_VSMACROS_STOP_MACRONAME \
193 "Macros.CMakeVSMacros2.Macros.StopBuild"
195 //----------------------------------------------------------------------------
196 void cmGlobalVisualStudioGenerator::ConfigureCMakeVisualStudioMacros()
198 cmMakefile* mf = this->LocalGenerators[0]->GetMakefile();
199 std::string dir = this->GetUserMacrosDirectory();
201 if (mf != 0 && dir != "")
203 std::string src = mf->GetRequiredDefinition("CMAKE_ROOT");
204 src += "/Templates/" CMAKE_VSMACROS_FILENAME;
206 std::string dst = dir + "/CMakeMacros/" CMAKE_VSMACROS_FILENAME;
208 // Copy the macros file to the user directory only if the
209 // destination does not exist or the source location is newer.
210 // This will allow the user to edit the macros for development
211 // purposes but newer versions distributed with CMake will replace
212 // older versions in user directories.
214 if(!cmSystemTools::FileTimeCompare(src.c_str(), dst.c_str(), &res) ||
217 if (!cmSystemTools::CopyFileAlways(src.c_str(), dst.c_str()))
219 std::ostringstream oss;
220 oss << "Could not copy from: " << src << std::endl;
221 oss << " to: " << dst << std::endl;
222 cmSystemTools::Message(oss.str().c_str(), "Warning");
226 RegisterVisualStudioMacros(dst, this->GetUserMacrosRegKeyBase());
230 //----------------------------------------------------------------------------
232 cmGlobalVisualStudioGenerator
233 ::CallVisualStudioMacro(MacroName m,
234 const char* vsSolutionFile)
236 // If any solution or project files changed during the generation,
237 // tell Visual Studio to reload them...
238 cmMakefile* mf = this->LocalGenerators[0]->GetMakefile();
239 std::string dir = this->GetUserMacrosDirectory();
241 // Only really try to call the macro if:
243 // - there is a UserMacrosDirectory
244 // - the CMake vsmacros file exists
245 // - the CMake vsmacros file is registered
246 // - there were .sln/.vcproj files changed during generation
248 if (mf != 0 && dir != "")
250 std::string macrosFile = dir + "/CMakeMacros/" CMAKE_VSMACROS_FILENAME;
251 std::string nextSubkeyName;
252 if (cmSystemTools::FileExists(macrosFile.c_str()) &&
253 IsVisualStudioMacrosFileRegistered(macrosFile,
254 this->GetUserMacrosRegKeyBase(), nextSubkeyName)
257 std::string topLevelSlnName;
260 topLevelSlnName = vsSolutionFile;
264 topLevelSlnName = mf->GetStartOutputDirectory();
265 topLevelSlnName += "/";
266 topLevelSlnName += mf->GetProjectName();
267 topLevelSlnName += ".sln";
272 std::vector<std::string> filenames;
273 this->GetFilesReplacedDuringGenerate(filenames);
274 if (filenames.size() > 0)
276 // Convert vector to semi-colon delimited string of filenames:
277 std::string projects;
278 std::vector<std::string>::iterator it = filenames.begin();
279 if (it != filenames.end())
284 for (; it != filenames.end(); ++it)
289 cmCallVisualStudioMacro::CallMacro(topLevelSlnName,
290 CMAKE_VSMACROS_RELOAD_MACRONAME, projects,
291 this->GetCMakeInstance()->GetDebugOutput());
294 else if(m == MacroStop)
296 cmCallVisualStudioMacro::CallMacro(topLevelSlnName,
297 CMAKE_VSMACROS_STOP_MACRONAME, "",
298 this->GetCMakeInstance()->GetDebugOutput());
304 //----------------------------------------------------------------------------
305 std::string cmGlobalVisualStudioGenerator::GetUserMacrosDirectory()
310 //----------------------------------------------------------------------------
311 std::string cmGlobalVisualStudioGenerator::GetUserMacrosRegKeyBase()
316 //----------------------------------------------------------------------------
317 void cmGlobalVisualStudioGenerator::FillLinkClosure(cmTarget* target,
320 if(linked.insert(target).second)
322 TargetDependSet const& depends = this->GetTargetDirectDepends(*target);
323 for(TargetDependSet::const_iterator di = depends.begin();
324 di != depends.end(); ++di)
328 this->FillLinkClosure(*di, linked);
334 //----------------------------------------------------------------------------
335 cmGlobalVisualStudioGenerator::TargetSet const&
336 cmGlobalVisualStudioGenerator::GetTargetLinkClosure(cmTarget* target)
338 TargetSetMap::iterator i = this->TargetLinkClosure.find(target);
339 if(i == this->TargetLinkClosure.end())
341 TargetSetMap::value_type entry(target, TargetSet());
342 i = this->TargetLinkClosure.insert(entry).first;
343 this->FillLinkClosure(target, i->second);
348 //----------------------------------------------------------------------------
349 void cmGlobalVisualStudioGenerator::FollowLinkDepends(
350 cmTarget* target, std::set<cmTarget*>& linked)
352 if(linked.insert(target).second &&
353 target->GetType() == cmTarget::STATIC_LIBRARY)
355 // Static library targets do not list their link dependencies so
356 // we must follow them transitively now.
357 TargetDependSet const& depends = this->GetTargetDirectDepends(*target);
358 for(TargetDependSet::const_iterator di = depends.begin();
359 di != depends.end(); ++di)
363 this->FollowLinkDepends(*di, linked);
369 //----------------------------------------------------------------------------
370 bool cmGlobalVisualStudioGenerator::ComputeTargetDepends()
372 if(!this->cmGlobalGenerator::ComputeTargetDepends())
376 std::map<cmStdString, std::vector<cmLocalGenerator*> >::iterator it;
377 for(it = this->ProjectMap.begin(); it!= this->ProjectMap.end(); ++it)
379 std::vector<cmLocalGenerator*>& gen = it->second;
380 for(std::vector<cmLocalGenerator*>::iterator i = gen.begin();
383 cmTargets& targets = (*i)->GetMakefile()->GetTargets();
384 for(cmTargets::iterator ti = targets.begin();
385 ti != targets.end(); ++ti)
387 this->ComputeVSTargetDepends(ti->second);
394 //----------------------------------------------------------------------------
395 static bool VSLinkable(cmTarget* t)
397 return t->IsLinkable() || t->GetType() == cmTarget::OBJECT_LIBRARY;
400 //----------------------------------------------------------------------------
401 void cmGlobalVisualStudioGenerator::ComputeVSTargetDepends(cmTarget& target)
403 if(this->VSTargetDepends.find(&target) != this->VSTargetDepends.end())
407 VSDependSet& vsTargetDepend = this->VSTargetDepends[&target];
408 // VS <= 7.1 has two behaviors that affect solution dependencies.
410 // (1) Solution-level dependencies between a linkable target and a
411 // library cause that library to be linked. We use an intermedite
412 // empty utility target to express the dependency. (VS 8 and above
413 // provide a project file "LinkLibraryDependencies" setting to
414 // choose whether to activate this behavior. We disable it except
415 // when linking external project files.)
417 // (2) We cannot let static libraries depend directly on targets to
418 // which they "link" because the librarian tool will copy the
419 // targets into the static library. While the work-around for
420 // behavior (1) would also avoid this, it would create a large
421 // number of extra utility targets for little gain. Instead, use
422 // the above work-around only for dependencies explicitly added by
423 // the add_dependencies() command. Approximate link dependencies by
424 // leaving them out for the static library itself but following them
425 // transitively for other targets.
427 bool allowLinkable = (target.GetType() != cmTarget::STATIC_LIBRARY &&
428 target.GetType() != cmTarget::SHARED_LIBRARY &&
429 target.GetType() != cmTarget::MODULE_LIBRARY &&
430 target.GetType() != cmTarget::EXECUTABLE);
432 TargetDependSet const& depends = this->GetTargetDirectDepends(target);
434 // Collect implicit link dependencies (target_link_libraries).
435 // Static libraries cannot depend on their link implementation
436 // due to behavior (2), but they do not really need to.
437 std::set<cmTarget*> linkDepends;
438 if(target.GetType() != cmTarget::STATIC_LIBRARY)
440 for(TargetDependSet::const_iterator di = depends.begin();
441 di != depends.end(); ++di)
443 cmTargetDepend dep = *di;
446 this->FollowLinkDepends(dep, linkDepends);
451 // Collect explicit util dependencies (add_dependencies).
452 std::set<cmTarget*> utilDepends;
453 for(TargetDependSet::const_iterator di = depends.begin();
454 di != depends.end(); ++di)
456 cmTargetDepend dep = *di;
459 this->FollowLinkDepends(dep, utilDepends);
463 // Collect all targets linked by this target so we can avoid
464 // intermediate targets below.
466 if(target.GetType() != cmTarget::STATIC_LIBRARY)
468 linked = this->GetTargetLinkClosure(&target);
471 // Emit link dependencies.
472 for(std::set<cmTarget*>::iterator di = linkDepends.begin();
473 di != linkDepends.end(); ++di)
476 vsTargetDepend.insert(dep->GetName());
479 // Emit util dependencies. Possibly use intermediate targets.
480 for(std::set<cmTarget*>::iterator di = utilDepends.begin();
481 di != utilDepends.end(); ++di)
484 if(allowLinkable || !VSLinkable(dep) || linked.count(dep))
486 // Direct dependency allowed.
487 vsTargetDepend.insert(dep->GetName());
491 // Direct dependency on linkable target not allowed.
492 // Use an intermediate utility target.
493 vsTargetDepend.insert(this->GetUtilityDepend(dep));
498 //----------------------------------------------------------------------------
499 void cmGlobalVisualStudioGenerator::AddPlatformDefinitions(cmMakefile* mf)
501 if(this->AdditionalPlatformDefinition)
503 mf->AddDefinition(this->AdditionalPlatformDefinition, "TRUE");
507 //----------------------------------------------------------------------------
508 std::string cmGlobalVisualStudioGenerator::GetUtilityDepend(cmTarget* target)
510 UtilityDependsMap::iterator i = this->UtilityDepends.find(target);
511 if(i == this->UtilityDepends.end())
513 std::string name = this->WriteUtilityDepend(target);
514 UtilityDependsMap::value_type entry(target, name);
515 i = this->UtilityDepends.insert(entry).first;
520 //----------------------------------------------------------------------------
523 //----------------------------------------------------------------------------
524 bool IsVisualStudioMacrosFileRegistered(const std::string& macrosFile,
525 const std::string& regKeyBase,
526 std::string& nextAvailableSubKeyName)
528 bool macrosRegistered = false;
533 // Make lowercase local copies, convert to Unix slashes, and
534 // see if the resulting strings are the same:
535 s1 = cmSystemTools::LowerCase(macrosFile);
536 cmSystemTools::ConvertToUnixSlashes(s1);
540 LONG result = ERROR_SUCCESS;
543 keyname = regKeyBase + "\\OtherProjects7";
545 result = RegOpenKeyEx(HKEY_CURRENT_USER, keyname.c_str(),
547 if (ERROR_SUCCESS == result)
549 // Iterate the subkeys and look for the values of interest in each subkey:
550 CHAR subkeyname[256];
551 DWORD cch_subkeyname = sizeof(subkeyname)/sizeof(subkeyname[0]);
553 DWORD cch_keyclass = sizeof(keyclass)/sizeof(keyclass[0]);
554 FILETIME lastWriteTime;
555 lastWriteTime.dwHighDateTime = 0;
556 lastWriteTime.dwLowDateTime = 0;
558 while (ERROR_SUCCESS == RegEnumKeyEx(hkey, index, subkeyname,
560 0, keyclass, &cch_keyclass, &lastWriteTime))
562 // Open the subkey and query the values of interest:
564 result = RegOpenKeyEx(hkey, subkeyname, 0, KEY_READ, &hsubkey);
565 if (ERROR_SUCCESS == result)
567 DWORD valueType = REG_SZ;
569 DWORD cch_data1 = sizeof(data1)/sizeof(data1[0]);
570 RegQueryValueEx(hsubkey, "Path", 0, &valueType,
571 (LPBYTE) &data1[0], &cch_data1);
574 DWORD cch_data2 = sizeof(data2);
575 RegQueryValueEx(hsubkey, "Security", 0, &valueType,
576 (LPBYTE) &data2, &cch_data2);
579 DWORD cch_data3 = sizeof(data3);
580 RegQueryValueEx(hsubkey, "StorageFormat", 0, &valueType,
581 (LPBYTE) &data3, &cch_data3);
583 s2 = cmSystemTools::LowerCase(data1);
584 cmSystemTools::ConvertToUnixSlashes(s2);
587 macrosRegistered = true;
590 std::string fullname(data1);
591 std::string filename;
592 std::string filepath;
593 std::string filepathname;
594 std::string filepathpath;
595 if (cmSystemTools::FileExists(fullname.c_str()))
597 filename = cmSystemTools::GetFilenameName(fullname);
598 filepath = cmSystemTools::GetFilenamePath(fullname);
599 filepathname = cmSystemTools::GetFilenameName(filepath);
600 filepathpath = cmSystemTools::GetFilenamePath(filepath);
603 //std::cout << keyname << "\\" << subkeyname << ":" << std::endl;
604 //std::cout << " Path: " << data1 << std::endl;
605 //std::cout << " Security: " << data2 << std::endl;
606 //std::cout << " StorageFormat: " << data3 << std::endl;
607 //std::cout << " filename: " << filename << std::endl;
608 //std::cout << " filepath: " << filepath << std::endl;
609 //std::cout << " filepathname: " << filepathname << std::endl;
610 //std::cout << " filepathpath: " << filepathpath << std::endl;
611 //std::cout << std::endl;
613 RegCloseKey(hsubkey);
617 std::cout << "error opening subkey: " << subkeyname << std::endl;
618 std::cout << std::endl;
622 cch_subkeyname = sizeof(subkeyname)/sizeof(subkeyname[0]);
623 cch_keyclass = sizeof(keyclass)/sizeof(keyclass[0]);
624 lastWriteTime.dwHighDateTime = 0;
625 lastWriteTime.dwLowDateTime = 0;
632 std::cout << "error opening key: " << keyname << std::endl;
633 std::cout << std::endl;
637 // Pass back next available sub key name, assuming sub keys always
638 // follow the expected naming scheme. Expected naming scheme is that
639 // the subkeys of OtherProjects7 is 0 to n-1, so it's ok to use "n"
640 // as the name of the next subkey.
641 std::ostringstream ossNext;
643 nextAvailableSubKeyName = ossNext.str();
646 keyname = regKeyBase + "\\RecordingProject7";
648 result = RegOpenKeyEx(HKEY_CURRENT_USER, keyname.c_str(),
650 if (ERROR_SUCCESS == result)
652 DWORD valueType = REG_SZ;
654 DWORD cch_data1 = sizeof(data1)/sizeof(data1[0]);
655 RegQueryValueEx(hkey, "Path", 0, &valueType,
656 (LPBYTE) &data1[0], &cch_data1);
659 DWORD cch_data2 = sizeof(data2);
660 RegQueryValueEx(hkey, "Security", 0, &valueType,
661 (LPBYTE) &data2, &cch_data2);
664 DWORD cch_data3 = sizeof(data3);
665 RegQueryValueEx(hkey, "StorageFormat", 0, &valueType,
666 (LPBYTE) &data3, &cch_data3);
668 s2 = cmSystemTools::LowerCase(data1);
669 cmSystemTools::ConvertToUnixSlashes(s2);
672 macrosRegistered = true;
675 //std::cout << keyname << ":" << std::endl;
676 //std::cout << " Path: " << data1 << std::endl;
677 //std::cout << " Security: " << data2 << std::endl;
678 //std::cout << " StorageFormat: " << data3 << std::endl;
679 //std::cout << std::endl;
685 std::cout << "error opening key: " << keyname << std::endl;
686 std::cout << std::endl;
689 return macrosRegistered;
692 //----------------------------------------------------------------------------
693 void WriteVSMacrosFileRegistryEntry(
694 const std::string& nextAvailableSubKeyName,
695 const std::string& macrosFile,
696 const std::string& regKeyBase)
698 std::string keyname = regKeyBase + "\\OtherProjects7";
700 LONG result = RegOpenKeyEx(HKEY_CURRENT_USER, keyname.c_str(), 0,
701 KEY_READ|KEY_WRITE, &hkey);
702 if (ERROR_SUCCESS == result)
704 // Create the subkey and set the values of interest:
707 result = RegCreateKeyEx(hkey, nextAvailableSubKeyName.c_str(), 0,
708 lpClass, 0, KEY_READ|KEY_WRITE, 0, &hsubkey, 0);
709 if (ERROR_SUCCESS == result)
713 std::string s(macrosFile);
714 cmSystemTools::ReplaceString(s, "/", "\\");
716 result = RegSetValueEx(hsubkey, "Path", 0, REG_SZ, (LPBYTE) s.c_str(),
717 static_cast<DWORD>(strlen(s.c_str()) + 1));
718 if (ERROR_SUCCESS != result)
720 std::cout << "error result 1: " << result << std::endl;
721 std::cout << std::endl;
724 // Security value is always "1" for sample macros files (seems to be "2"
725 // if you put the file somewhere outside the standard VSMacros folder)
727 result = RegSetValueEx(hsubkey, "Security",
728 0, REG_DWORD, (LPBYTE) &dw, sizeof(DWORD));
729 if (ERROR_SUCCESS != result)
731 std::cout << "error result 2: " << result << std::endl;
732 std::cout << std::endl;
735 // StorageFormat value is always "0" for sample macros files
737 result = RegSetValueEx(hsubkey, "StorageFormat",
738 0, REG_DWORD, (LPBYTE) &dw, sizeof(DWORD));
739 if (ERROR_SUCCESS != result)
741 std::cout << "error result 3: " << result << std::endl;
742 std::cout << std::endl;
745 RegCloseKey(hsubkey);
749 std::cout << "error creating subkey: "
750 << nextAvailableSubKeyName << std::endl;
751 std::cout << std::endl;
757 std::cout << "error opening key: " << keyname << std::endl;
758 std::cout << std::endl;
762 //----------------------------------------------------------------------------
763 void RegisterVisualStudioMacros(const std::string& macrosFile,
764 const std::string& regKeyBase)
766 bool macrosRegistered;
767 std::string nextAvailableSubKeyName;
769 macrosRegistered = IsVisualStudioMacrosFileRegistered(macrosFile,
770 regKeyBase, nextAvailableSubKeyName);
772 if (!macrosRegistered)
774 int count = cmCallVisualStudioMacro::
775 GetNumberOfRunningVisualStudioInstances("ALL");
777 // Only register the macros file if there are *no* instances of Visual
778 // Studio running. If we register it while one is running, first, it has
779 // no effect on the running instance; second, and worse, Visual Studio
780 // removes our newly added registration entry when it quits. Instead,
781 // emit a warning asking the user to exit all running Visual Studio
786 std::ostringstream oss;
787 oss << "Could not register CMake's Visual Studio macros file '"
788 << CMAKE_VSMACROS_FILENAME "' while Visual Studio is running."
789 << " Please exit all running instances of Visual Studio before"
790 << " continuing." << std::endl
792 << "CMake needs to register Visual Studio macros when its macros"
793 << " file is updated or when it detects that its current macros file"
794 << " is no longer registered with Visual Studio."
796 cmSystemTools::Message(oss.str().c_str(), "Warning");
798 // Count them again now that the warning is over. In the case of a GUI
799 // warning, the user may have gone to close Visual Studio and then come
800 // back to the CMake GUI and clicked ok on the above warning. If so,
801 // then register the macros *now* if the count is *now* 0...
803 count = cmCallVisualStudioMacro::
804 GetNumberOfRunningVisualStudioInstances("ALL");
806 // Also re-get the nextAvailableSubKeyName in case Visual Studio
807 // wrote out new registered macros information as it was exiting:
811 IsVisualStudioMacrosFileRegistered(macrosFile, regKeyBase,
812 nextAvailableSubKeyName);
816 // Do another if check - 'count' may have changed inside the above if:
820 WriteVSMacrosFileRegistryEntry(nextAvailableSubKeyName, macrosFile,
825 bool cmGlobalVisualStudioGenerator::TargetIsFortranOnly(cmTarget& target)
827 // check to see if this is a fortran build
828 std::set<cmStdString> languages;
829 target.GetLanguages(languages);
830 if(languages.size() == 1)
832 if(*languages.begin() == "Fortran")
840 //----------------------------------------------------------------------------
842 cmGlobalVisualStudioGenerator::TargetCompare
843 ::operator()(cmTarget const* l, cmTarget const* r) const
845 // Make sure ALL_BUILD is first so it is the default active project.
846 if(strcmp(r->GetName(), "ALL_BUILD") == 0)
850 if(strcmp(l->GetName(), "ALL_BUILD") == 0)
854 return strcmp(l->GetName(), r->GetName()) < 0;
857 //----------------------------------------------------------------------------
858 cmGlobalVisualStudioGenerator::OrderedTargetDependSet
859 ::OrderedTargetDependSet(TargetDependSet const& targets)
861 for(TargetDependSet::const_iterator ti =
862 targets.begin(); ti != targets.end(); ++ti)
868 //----------------------------------------------------------------------------
869 cmGlobalVisualStudioGenerator::OrderedTargetDependSet
870 ::OrderedTargetDependSet(TargetSet const& targets)
872 for(TargetSet::const_iterator ti = targets.begin();
873 ti != targets.end(); ++ti)